using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OFACScraper.Configuration;
using OFACScraper.Helpers;
using OFACScraper.Models;
using OFACScraper.Services;

namespace OFACScraper;

public class Exporter
{
    private readonly HttpClient _http;
    private readonly S3UploadService _s3;
    private readonly StorageOptions _storage;
    private readonly S3Options _s3Options;
    private readonly ILogger<Exporter> _logger;

    public Exporter(
        HttpClient http,
        S3UploadService s3,
        IOptions<StorageOptions> storage,
        IOptions<S3Options> s3Options,
        ILogger<Exporter> logger)
    {
        _http = http;
        _s3 = s3;
        _storage = storage.Value;
        _s3Options = s3Options.Value;
        _logger = logger;
    }

    /// <summary>
    /// Exports a single OFAC record: downloads PDF, writes metadata.json, syncs to S3.
    /// Returns true if the record was exported successfully.
    /// </summary>
    public async Task<bool> ExportRecordAsync(OFACRecord record, CancellationToken ct = default)
    {
        var pubId = DeterministicGuid.FromUrl(record.YearPageUrl + "#" + record.TextId);
        var docId = DeterministicGuid.FromUrl(record.DocumentUrl);

        var exportDir = Path.Combine(_storage.ExportDirectory, pubId.ToString());
        Directory.CreateDirectory(exportDir);

        // Download PDF
        var localPdfPath = Path.Combine(exportDir, record.FileName);
        if (!File.Exists(localPdfPath))
        {
            if (!await DownloadFileAsync(record.DocumentUrl, localPdfPath, ct))
            {
                _logger.LogError("Failed to download PDF for {TextId}", record.TextId);
                return false;
            }
        }

        // Build publication metadata
        var pub = new Publication
        {
            Id = pubId,
            TextId = record.TextId,
            Source = PublicationSources.OfacCivilPenalty,
            WebsiteLink = record.YearPageUrl,
            Title = $"{record.Name} - OFAC Civil Penalty {record.Date:yyyy-MM-dd}",
            DatePublished = new DateTimeOffset(record.Date, TimeSpan.Zero),
            DateAccessed = DateTimeOffset.UtcNow,
            ScraperVersion = ScraperConstants.ScraperVersion,
            Documents =
            [
                new PublicationDocument
                {
                    Id = docId,
                    Name = record.FileName,
                    Url = record.DocumentUrl
                }
            ],
            Tags =
            [
                new PublicationTag { Slug = "penalty-date", Date = new DateTimeOffset(record.Date, TimeSpan.Zero) },
                new PublicationTag { Slug = "entity-name", Text = record.Name },
                new PublicationTag { Slug = "penalty-amount-usd", Text = record.PenaltyTotalUsd?.ToString("F2") ?? "N/A" },
                new PublicationTag { Slug = "year", Text = record.Year.ToString() }
            ]
        };

        // Write metadata.json (last — S3 sync uploads it after the PDF)
        var metadataPath = Path.Combine(exportDir, "metadata.json");
        var json = JsonSerializer.Serialize(pub, JsonConstants.Default);
        await File.WriteAllTextAsync(metadataPath, json, ct);

        // Sync this record's directory to S3
        var s3Prefix = $"{_s3Options.Prefix}/{pubId}";
        var syncResult = await _s3.SyncDirectoryAsync(exportDir, s3Prefix);

        if (syncResult.Failed > 0)
        {
            _logger.LogError("S3 sync failed for {TextId}: {Failed} files failed", record.TextId, syncResult.Failed);
            return false;
        }

        _logger.LogInformation("Exported {TextId} → S3 ({Uploaded} uploaded, {Skipped} unchanged)",
            record.TextId, syncResult.Uploaded, syncResult.Skipped);
        return true;
    }

    private async Task<bool> DownloadFileAsync(string url, string localPath, CancellationToken ct)
    {
        try
        {
            var bytes = await _http.GetByteArrayAsync(url, ct);
            await File.WriteAllBytesAsync(localPath, bytes, ct);
            _logger.LogDebug("Downloaded {Url} → {Path}", url, localPath);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error downloading {Url}", url);
            return false;
        }
    }
}
