using System.Globalization;
using Microsoft.Extensions.Logging;
using OTSSignsOrchestrator.Core.Models.Entities;
using OTSSignsOrchestrator.Core.Services;

namespace OTSSignsOrchestrator.Desktop.Services;

/// <summary>
/// Docker Swarm secrets management over SSH.
/// Uses docker CLI commands executed remotely instead of Docker.DotNet.
/// </summary>
public class SshDockerSecretsService : IDockerSecretsService
{
    private readonly SshConnectionService _ssh;
    private readonly ILogger<SshDockerSecretsService> _logger;
    private SshHost? _currentHost;

    public SshDockerSecretsService(SshConnectionService ssh, ILogger<SshDockerSecretsService> logger)
    {
        _ssh = ssh;
        _logger = logger;
    }

    public void SetHost(SshHost host) => _currentHost = host;
    public SshHost? CurrentHost => _currentHost;

    public async Task<(bool Created, string SecretId)> EnsureSecretAsync(string name, string value, bool rotate = false)
    {
        EnsureHost();

        _logger.LogInformation("Ensuring secret exists via SSH: {SecretName}", name);

        // Check if secret already exists
        var existing = await FindSecretAsync(name);

        if (existing != null && !rotate)
        {
            _logger.LogDebug("Secret already exists: {SecretName} (id={SecretId})", name, existing.Value.id);
            return (false, existing.Value.id);
        }

        if (existing != null && rotate)
        {
            _logger.LogInformation("Rotating secret via SSH: {SecretName} (old id={SecretId})", name, existing.Value.id);
            var (rmExit, _, rmErr) = await _ssh.RunCommandAsync(_currentHost!, $"docker secret rm {name}");
            if (rmExit != 0)
            {
                _logger.LogError("Failed to remove old secret for rotation: {SecretName} | error={Error}", name, rmErr);
                return (false, string.Empty);
            }
        }

        // Create secret via stdin
        var safeValue = value.Replace("'", "'\\''");
        var (exitCode, stdout, stderr) = await _ssh.RunCommandAsync(
            _currentHost!, $"printf '%s' '{safeValue}' | docker secret create {name} -");

        if (exitCode != 0)
        {
            _logger.LogError("Failed to create secret via SSH: {SecretName} | error={Error}", name, stderr);
            return (false, string.Empty);
        }

        var secretId = stdout.Trim();
        _logger.LogInformation("Secret created via SSH: {SecretName} (id={SecretId})", name, secretId);
        return (true, secretId);
    }

    public async Task<List<SecretListItem>> ListSecretsAsync()
    {
        EnsureHost();

        var (exitCode, stdout, _) = await _ssh.RunCommandAsync(
            _currentHost!, "docker secret ls --format '{{.ID}}\\t{{.Name}}\\t{{.CreatedAt}}'");

        if (exitCode != 0 || string.IsNullOrWhiteSpace(stdout))
            return new List<SecretListItem>();

        return stdout
            .Split('\n', StringSplitOptions.RemoveEmptyEntries)
            .Select(line =>
            {
                var parts = line.Split('\t', 3);
                return new SecretListItem
                {
                    Id = parts.Length > 0 ? parts[0].Trim() : "",
                    Name = parts.Length > 1 ? parts[1].Trim() : "",
                    CreatedAt = parts.Length > 2 && DateTime.TryParse(parts[2].Trim(), CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt)
                        ? dt
                        : DateTime.MinValue
                };
            })
            .ToList();
    }

    public async Task<bool> DeleteSecretAsync(string name)
    {
        EnsureHost();

        var existing = await FindSecretAsync(name);
        if (existing == null)
        {
            _logger.LogDebug("Secret not found for deletion: {SecretName}", name);
            return true; // idempotent
        }

        var (exitCode, _, stderr) = await _ssh.RunCommandAsync(_currentHost!, $"docker secret rm {name}");
        if (exitCode != 0)
        {
            _logger.LogError("Failed to delete secret via SSH: {SecretName} | error={Error}", name, stderr);
            return false;
        }

        _logger.LogInformation("Secret deleted via SSH: {SecretName}", name);
        return true;
    }

    private async Task<(string id, string name)?> FindSecretAsync(string name)
    {
        var (exitCode, stdout, _) = await _ssh.RunCommandAsync(
            _currentHost!, $"docker secret ls --filter 'name={name}' --format '{{{{.ID}}}}\\t{{{{.Name}}}}'");

        if (exitCode != 0 || string.IsNullOrWhiteSpace(stdout))
            return null;

        var line = stdout.Split('\n', StringSplitOptions.RemoveEmptyEntries)
            .FirstOrDefault(l =>
            {
                var parts = l.Split('\t', 2);
                return parts.Length > 1 && string.Equals(parts[1].Trim(), name, StringComparison.OrdinalIgnoreCase);
            });

        if (line == null) return null;

        var p = line.Split('\t', 2);
        return (p[0].Trim(), p[1].Trim());
    }

    private void EnsureHost()
    {
        if (_currentHost == null)
            throw new InvalidOperationException("No SSH host configured. Call SetHost() before using Docker secrets.");
    }
}
