using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using CamBooth.App.Core.AppSettings;
using CamBooth.App.Core.Logging;

namespace CamBooth.App.Features.PhotoPrismUpload;

/// <summary>
/// Service für den Upload von Bildern zu PhotoPrism mit Token-basierter Authentifizierung.
/// </summary>
public class PhotoPrismUploadService : IDisposable
{
    private readonly AppSettingsService _appSettings;
    private readonly Logger _logger;
    private readonly HttpClient _httpClient;
    private readonly PhotoPrismAuthService _authService;
    private readonly QRCodeGenerationService _qrCodeGenerationService;
    private string? _uploadUserUid;
    private string? _uploadToken;
    private string? _targetAlbumUid;
    private string? _targetShareToken;
    private bool _isAuthenticated = false;

    public bool IsAuthenticated => _isAuthenticated;
    public BitmapImage? LastGeneratedQRCode { get; private set; }

    public PhotoPrismUploadService(
        AppSettingsService appSettings,
        Logger logger,
        PhotoPrismAuthService authService)
    {
        _appSettings = appSettings;
        _logger = logger;
        _authService = authService;
        _qrCodeGenerationService = new QRCodeGenerationService(logger);
        _httpClient = new HttpClient { Timeout = TimeSpan.FromMinutes(5) };
    }

    // =========================================================================
    // Public API
    // =========================================================================

    /// <summary>
    /// Authentifiziert sich bei PhotoPrism.
    /// </summary>
    public async Task<bool> AuthenticateAsync()
    {
        try
        {
            // Bei API-Key direkt authentifizieren ohne Validierung
            if (!string.IsNullOrWhiteSpace(_appSettings.PhotoPrismApiKey))
            {
                _logger.Info("Nutze PhotoPrism API-Key...");
                var success = await _authService.AuthenticateAsync();
                if (success)
                {
                    _isAuthenticated = true;
                    _httpClient.DefaultRequestHeaders.Remove("X-Auth-Token");
                    _httpClient.DefaultRequestHeaders.Add("X-Auth-Token", _authService.AccessToken);
                    _logger.Info("✅ PhotoPrism API-Key aktiviert");
                }
                return success;
            }

            // Sonst mit Credentials authentifizieren
            _logger.Info("Starte PhotoPrism-Authentifizierung mit Credentials...");
            
            // Validiere dass es eine PhotoPrism-Instanz ist (nur bei Credentials)
            if (!await ValidatePhotoPrismInstanceAsync())
            {
                _logger.Error("❌ API-URL ist keine gültige PhotoPrism-Instanz!");
                _logger.Error($"   URL: {_appSettings.PhotoPrismApiUrl}");
                return false;
            }

            var success2 = await _authService.AuthenticateAsync();
            if (success2)
            {
                _isAuthenticated = true;
                _httpClient.DefaultRequestHeaders.Remove("X-Auth-Token");
                _httpClient.DefaultRequestHeaders.Add("X-Auth-Token", _authService.AccessToken);
            }
            return success2;
        }
        catch (Exception ex)
        {
            _logger.Error($"Fehler bei PhotoPrism-Authentifizierung: {ex.Message}");
            return false;
        }
    }

    /// <summary>
    /// Validiert, dass die URL eine echte PhotoPrism-Instanz ist.
    /// </summary>
    private async Task<bool> ValidatePhotoPrismInstanceAsync()
    {
        try
        {
            var response = await _httpClient.GetAsync($"{_appSettings.PhotoPrismApiUrl}/api/v1/status");
            
            if (!response.IsSuccessStatusCode)
            {
                if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    _logger.Warning("⚠️ /api/v1/status nicht gefunden - könnte Lychee sein!");
                }
                return false;
            }

            _logger.Debug("✅ PhotoPrism-Instanz validiert!");
            return true;
        }
        catch (Exception ex)
        {
            _logger.Warning($"Konnte PhotoPrism-Instanz nicht validieren: {ex.Message}");
            return false;
        }
    }

    /// <summary>
    /// Uploaded ein einzelnes Bild zu PhotoPrism.
    /// </summary>
    public async Task<bool> UploadImageAsync(string imagePath)
    {
        try
        {
            if (!_isAuthenticated && !await AuthenticateAsync())
                return false;

            if (!File.Exists(imagePath))
            {
                _logger.Error($"Bild nicht gefunden: {imagePath}");
                return false;
            }

            _logger.Debug($"Starte Upload: {Path.GetFileName(imagePath)}");
            _logger.Debug($"   Authentifiziert: {_isAuthenticated}");
            _logger.Debug($"   Token vorhanden: {!string.IsNullOrEmpty(_authService.AccessToken)}");

            if (!await EnsureUploadEndpointAsync())
            {
                return false;
            }

            var uploadUrl = $"{_appSettings.PhotoPrismApiUrl}/api/v1/users/{_uploadUserUid}/upload/{_uploadToken}";
            _logger.Debug($"   Upload-URL: {uploadUrl}");

            var fileInfo = new FileInfo(imagePath);
            var imageBytes = await File.ReadAllBytesAsync(imagePath);

            using var form = new MultipartFormDataContent();
            
            var imageContent = new ByteArrayContent(imageBytes);
            imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
            imageContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = "files",
                FileName = fileInfo.Name
            };
            form.Add(imageContent);

            var response = await _httpClient.PostAsync(uploadUrl, form);

            _logger.Debug($"   Response-Status: {response.StatusCode}");
            _logger.Debug($"   Headers gesendet: {string.Join(", ", _httpClient.DefaultRequestHeaders.Select(h => h.Key))}");

            if (!response.IsSuccessStatusCode)
            {
                var errorContent = await response.Content.ReadAsStringAsync();

                // Aussagekräftige Fehlermeldungen
                if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    _logger.Error($"❌ Upload fehlgeschlagen: Endpoint nicht gefunden (404)");
                    _logger.Error($"   Überprüfe die PhotoPrism API-URL: {_appSettings.PhotoPrismApiUrl}");
                    _logger.Error("   Erwarteter Endpoint: /api/v1/users/{uid}/upload/{token}");
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    _logger.Error($"❌ Upload fehlgeschlagen: Authentifizierung fehlgeschlagen (401)");
                    _logger.Error($"   Überprüfe deinen API-Key oder deine Credentials");
                }
                else
                {
                    _logger.Error($"Upload fehlgeschlagen ({response.StatusCode}): {errorContent}");
                }

                return false;
            }

            var albumUid = await ResolveAlbumUidFromShareUrlAsync();
            if (!await ProcessUploadedFilesAsync(albumUid))
            {
                return false;
            }

            _logger.Info($"Upload erfolgreich: {Path.GetFileName(imagePath)}");
            return true;
        }
        catch (Exception ex)
        {
            _logger.Error($"Fehler beim Upload: {ex.Message}");
            return false;
        }
    }

    private async Task<bool> EnsureUploadEndpointAsync()
    {
        if (!string.IsNullOrWhiteSpace(_uploadUserUid) && !string.IsNullOrWhiteSpace(_uploadToken))
        {
            return true;
        }

        try
        {
            var response = await _httpClient.GetAsync($"{_appSettings.PhotoPrismApiUrl}/api/v1/session");
            if (!response.IsSuccessStatusCode)
            {
                _logger.Error($"Konnte Upload-Session nicht abrufen ({response.StatusCode})");
                return false;
            }

            var json = await response.Content.ReadAsStringAsync();
            using var document = JsonDocument.Parse(json);
            var root = document.RootElement;

            var uid = TryReadNestedString(root, "user", "UID") ?? TryReadNestedString(root, "user", "uid");
            var sessionToken = TryReadString(root, "id");

            _uploadUserUid = uid;
            _uploadToken = !string.IsNullOrWhiteSpace(_uploadToken)
                ? _uploadToken
                : (!string.IsNullOrWhiteSpace(sessionToken) ? sessionToken : Guid.NewGuid().ToString("N"));

            if (string.IsNullOrWhiteSpace(_uploadUserUid) || string.IsNullOrWhiteSpace(_uploadToken))
            {
                _logger.Error("Konnte Upload-UID/Token aus /api/v1/session nicht ermitteln.");
                return false;
            }

            _logger.Debug($"Upload-Kontext geladen: uid={_uploadUserUid}");
            return true;
        }
        catch (Exception ex)
        {
            _logger.Error($"Fehler beim Laden des Upload-Kontexts: {ex.Message}");
            return false;
        }
    }

    private async Task<string?> ResolveAlbumUidFromShareUrlAsync()
    {
        if (string.IsNullOrWhiteSpace(_appSettings.PhotoPrismAlbumShareUrl))
        {
            return null;
        }

        var shareToken = ExtractShareToken(_appSettings.PhotoPrismAlbumShareUrl!);
        if (string.IsNullOrWhiteSpace(shareToken))
        {
            _logger.Warning("PhotoPrism Album-Share-URL konnte nicht geparst werden. Upload wird nicht zu einem Album zugeordnet.");
            return null;
        }

        if (string.Equals(_targetShareToken, shareToken, StringComparison.OrdinalIgnoreCase) &&
            !string.IsNullOrWhiteSpace(_targetAlbumUid))
        {
            return _targetAlbumUid;
        }

        _targetShareToken = shareToken;
        _targetAlbumUid = null;

        try
        {
            var albumsResponse = await _httpClient.GetAsync($"{_appSettings.PhotoPrismApiUrl}/api/v1/albums?count=1000");
            if (!albumsResponse.IsSuccessStatusCode)
            {
                _logger.Warning($"Konnte Album-Liste nicht laden ({albumsResponse.StatusCode}).");
                return null;
            }

            var albumsJson = await albumsResponse.Content.ReadAsStringAsync();
            using var albumsDoc = JsonDocument.Parse(albumsJson);
            if (albumsDoc.RootElement.ValueKind != JsonValueKind.Array)
            {
                return null;
            }

            foreach (var album in albumsDoc.RootElement.EnumerateArray())
            {
                var albumUid = TryReadString(album, "UID") ?? TryReadString(album, "uid");
                if (string.IsNullOrWhiteSpace(albumUid))
                {
                    continue;
                }

                var linksResponse = await _httpClient.GetAsync($"{_appSettings.PhotoPrismApiUrl}/api/v1/albums/{albumUid}/links");
                if (!linksResponse.IsSuccessStatusCode)
                {
                    continue;
                }

                var linksJson = await linksResponse.Content.ReadAsStringAsync();
                using var linksDoc = JsonDocument.Parse(linksJson);
                if (linksDoc.RootElement.ValueKind != JsonValueKind.Array)
                {
                    continue;
                }

                foreach (var link in linksDoc.RootElement.EnumerateArray())
                {
                    var token = TryReadString(link, "Token") ?? TryReadString(link, "token");
                    if (string.Equals(token, shareToken, StringComparison.OrdinalIgnoreCase))
                    {
                        _targetAlbumUid = albumUid;
                        _logger.Debug($"Zielalbum für Share-Link gefunden: {_targetAlbumUid}");
                        return _targetAlbumUid;
                    }
                }
            }

            _logger.Warning($"Kein Album für Share-Token '{shareToken}' gefunden.");
            return null;
        }
        catch (Exception ex)
        {
            _logger.Warning($"Konnte Zielalbum über Share-Link nicht auflösen: {ex.Message}");
            return null;
        }
    }

    private static string? ExtractShareToken(string shareUrl)
    {
        if (string.IsNullOrWhiteSpace(shareUrl))
        {
            return null;
        }

        var match = Regex.Match(shareUrl, @"/s/([^/]+)", RegexOptions.IgnoreCase);
        return match.Success ? match.Groups[1].Value : null;
    }

    private async Task<bool> ProcessUploadedFilesAsync(string? albumUid)
    {
        if (string.IsNullOrWhiteSpace(_uploadUserUid) || string.IsNullOrWhiteSpace(_uploadToken))
        {
            _logger.Error("Upload-Kontext für Import fehlt (uid/token).");
            return false;
        }

        var payload = new { albums = string.IsNullOrWhiteSpace(albumUid) ? Array.Empty<string>() : new[] { albumUid } };
        var json = JsonSerializer.Serialize(payload);
        using var content = new StringContent(json, Encoding.UTF8, "application/json");

        var processUrl = $"{_appSettings.PhotoPrismApiUrl}/api/v1/users/{_uploadUserUid}/upload/{_uploadToken}";
        var response = await _httpClient.PutAsync(processUrl, content);

        if (!response.IsSuccessStatusCode)
        {
            var error = await response.Content.ReadAsStringAsync();
            _logger.Error($"Verarbeitung des Uploads fehlgeschlagen ({response.StatusCode}): {error}");
            return false;
        }

        if (!string.IsNullOrWhiteSpace(albumUid))
        {
            _logger.Debug($"Upload wurde verarbeitet und Album {albumUid} zugeordnet.");
        }
        else
        {
            _logger.Debug("Upload wurde verarbeitet (ohne Album-Zuordnung).");
        }

        return true;
    }

    private static string? TryReadString(JsonElement element, string propertyName)
    {
        if (TryGetPropertyIgnoreCase(element, propertyName, out var value) && value.ValueKind == JsonValueKind.String)
        {
            return value.GetString();
        }

        return null;
    }

    private static string? TryReadNestedString(JsonElement root, string objectPropertyName, string valuePropertyName)
    {
        if (!TryGetPropertyIgnoreCase(root, objectPropertyName, out var obj) || obj.ValueKind != JsonValueKind.Object)
        {
            return null;
        }

        return TryReadString(obj, valuePropertyName);
    }

    private static bool TryGetPropertyIgnoreCase(JsonElement element, string propertyName, out JsonElement value)
    {
        foreach (var property in element.EnumerateObject())
        {
            if (string.Equals(property.Name, propertyName, StringComparison.OrdinalIgnoreCase))
            {
                value = property.Value;
                return true;
            }
        }

        value = default;
        return false;
    }

    /// <summary>
    /// Uploaded mehrere Bilder zu PhotoPrism.
    /// </summary>
    public async Task<int> UploadImagesAsync(IEnumerable<string> imagePaths)
    {
        int successCount = 0;
        foreach (var path in imagePaths)
        {
            if (await UploadImageAsync(path))
                successCount++;
            
            await Task.Delay(500);
        }

        _logger.Info($"{successCount} von {imagePaths.Count()} Bildern hochgeladen.");
        return successCount;
    }

    /// <summary>
    /// Generiert einen QR-Code für das PhotoPrism Album.
    /// </summary>
    public BitmapImage? GenerateAlbumQRCode()
    {
        try
        {
            if (string.IsNullOrEmpty(_appSettings.PhotoPrismApiUrl))
            {
                _logger.Error("PhotoPrism-URL ist nicht konfiguriert.");
                return null;
            }

            var albumUrl = _appSettings.PhotoPrismAlbumShareUrl;
            if (string.IsNullOrEmpty(albumUrl))
            {
                _logger.Warning("PhotoPrism Album-Share-URL nicht konfiguriert");
                return null;
            }

            _logger.Debug($"QR-Code URL: {albumUrl}");
            return LastGeneratedQRCode = _qrCodeGenerationService.GenerateQRCode(albumUrl);
        }
        catch (Exception ex)
        {
            _logger.Error($"Fehler beim Generieren des QR-Codes: {ex.Message}");
            return null;
        }
    }

    /// <summary>
    /// Meldet sich von PhotoPrism ab.
    /// </summary>
    public async Task LogoutAsync()
    {
        try
        {
            await _authService.LogoutAsync();
            _isAuthenticated = false;
            _uploadUserUid = null;
            _uploadToken = null;
            _targetAlbumUid = null;
            _targetShareToken = null;
            _httpClient.DefaultRequestHeaders.Remove("X-Auth-Token");
        }
        catch (Exception ex)
        {
            _logger.Error($"Fehler beim Abmelden: {ex.Message}");
        }
    }

    public void Dispose()
    {
        _httpClient?.Dispose();
        _authService?.Dispose();
    }
}
