using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

namespace Elfisa.Core;

/// <summary>
/// Клиент платформы. Портирован из WinForms-версии, оставлены методы,
/// нужные новому Avalonia-клиенту: логин, отчёт покупателя, ИИ-отчёт.
/// Остальные эндпоинты добавляются по мере портирования экранов.
/// </summary>
public sealed class ApiClient
{
    private static readonly JsonSerializerOptions Json = new() { PropertyNamingPolicy = null };

    private readonly HttpClient _http;
    private readonly string _baseUrl;
    private string? _token;

    public ApiClient(string? baseUrl = null)
    {
        _baseUrl = (baseUrl ?? AppConfig.ApiBaseUrl).TrimEnd('/');
        _http = new HttpClient { Timeout = TimeSpan.FromSeconds(120) };
    }

    public string BaseUrl => _baseUrl;
    public string? Token => _token;
    public bool IsAuthenticated => !string.IsNullOrEmpty(_token);

    public void SetToken(string? token) => _token = string.IsNullOrWhiteSpace(token) ? null : token;

    private string Url(string path) => new Uri(new Uri(_baseUrl + "/"), path.TrimStart('/')).ToString();

    /// <summary>Логин. Возвращает (token, role) либо бросает с понятным сообщением.</summary>
    public async Task<LoginResponse> LoginAsync(string username, string password)
    {
        var body = JsonSerializer.Serialize(new LoginRequest { Username = username, Password = password }, Json);
        using var req = new HttpRequestMessage(HttpMethod.Post, Url("/auth/login"))
        {
            Content = new StringContent(body, Encoding.UTF8, "application/json")
        };
        HttpResponseMessage resp;
        try { resp = await _http.SendAsync(req).ConfigureAwait(false); }
        catch (Exception ex) { throw new ApiException($"Не удалось связаться с сервером ({_baseUrl}): {ex.Message}", ex); }

        var text = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
        if (resp.StatusCode == HttpStatusCode.Unauthorized)
            throw new ApiException("Неверный логин или пароль.");
        if (resp.StatusCode == (HttpStatusCode)429)
            throw new ApiException("Слишком много запросов. Подождите немного и повторите.");
        if (!resp.IsSuccessStatusCode)
            throw new ApiException(TryError(text) ?? $"Ошибка авторизации ({(int)resp.StatusCode}).");

        var login = JsonSerializer.Deserialize<LoginResponse>(text, Json);
        if (login is null || string.IsNullOrWhiteSpace(login.Token))
            throw new ApiException("Сервер вернул пустой токен.");
        _token = login.Token;
        return login;
    }

    /// <summary>Отчёт покупателя за период (скоуп по JWT на сервере — только свои заказы).</summary>
    public async Task<List<BuyerReportLineDto>> GetBuyerReportAsync(DateTime from, DateTime to)
    {
        EnsureAuth();
        var path = $"/api/buyer/report?date_from={from:yyyy-MM-dd}&date_to={to:yyyy-MM-dd}";
        var text = await AuthorizedGetAsync(path, "формирование отчёта").ConfigureAwait(false);
        var resp = JsonSerializer.Deserialize<BuyerReportResponse>(text, Json);
        return resp?.Lines ?? new List<BuyerReportLineDto>();
    }

    /// <summary>Свободный запрос к ИИ -> готовый Word/Excel (сервис на Mac mini через /ai).</summary>
    public async Task<AiReportResult> GenerateAiReportAsync(string prompt, string format = "docx")
    {
        EnsureAuth();
        if (string.IsNullOrWhiteSpace(prompt)) throw new ApiException("Пустой запрос для ИИ.");
        var aiUrl = new Uri(new Uri(AppConfig.AiBaseUrl.TrimEnd('/') + "/"), "generate").ToString();
        var body = JsonSerializer.Serialize(new AiReportRequest { Prompt = prompt, Token = _token!, Format = format }, Json);
        using var req = new HttpRequestMessage(HttpMethod.Post, aiUrl)
        {
            Content = new StringContent(body, Encoding.UTF8, "application/json")
        };
        HttpResponseMessage resp;
        try { resp = await _http.SendAsync(req).ConfigureAwait(false); }
        catch (Exception ex) { throw new ApiException($"ИИ-сервис недоступен: {ex.Message}", ex); }

        if (!resp.IsSuccessStatusCode)
        {
            var err = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
            throw new ApiException($"ИИ-сервис вернул {(int)resp.StatusCode}: {TryError(err) ?? err}");
        }
        var bytes = await resp.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
        var name = resp.Content.Headers.ContentDisposition?.FileNameStar
                   ?? resp.Content.Headers.ContentDisposition?.FileName
                   ?? (format == "xlsx" ? "Отчёт.xlsx" : "Отчёт.docx");
        return new AiReportResult { Content = bytes, FileName = name.Trim('"') };
    }

    /// <summary>Сводный прайс (то же, что грузит WinForms-десктоп). Поиск по q (от 2 символов).</summary>
    public async Task<PriceSummaryResponse> GetPriceSummaryAsync(string? q = null, int limit = 200, int offset = 0)
    {
        EnsureAuth();
        var path = $"/api/supplier-prices/summary?limit={limit}&offset={offset}";
        if (!string.IsNullOrWhiteSpace(q) && q.Trim().Length >= 2)
            path += "&q=" + Uri.EscapeDataString(q.Trim());
        var text = await AuthorizedGetAsync(path, "загрузку прайса").ConfigureAwait(false);
        return JsonSerializer.Deserialize<PriceSummaryResponse>(text, Json) ?? new PriceSummaryResponse();
    }

    /// <summary>Создаёт заказ (Placed). ВНИМАНИЕ: создаёт реальный заказ у поставщика.</summary>
    public async Task<BuyerOrderResponse> CreateOrderAsync(BuyerOrderCreateRequest request)
    {
        EnsureAuth();
        if (request.Items.Count == 0) throw new ApiException("Корзина пуста.");
        var body = JsonSerializer.Serialize(request, Json);
        using var req = new HttpRequestMessage(HttpMethod.Post, Url("/api/buyer/orders"))
        {
            Content = new StringContent(body, Encoding.UTF8, "application/json")
        };
        req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
        HttpResponseMessage resp;
        try { resp = await _http.SendAsync(req).ConfigureAwait(false); }
        catch (Exception ex) { throw new ApiException($"Не удалось отправить заказ: {ex.Message}", ex); }

        var text = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
        if (resp.StatusCode == HttpStatusCode.Unauthorized) { _token = null; throw new ApiException("Сессия истекла, войдите снова."); }
        if (!resp.IsSuccessStatusCode) throw new ApiException(TryError(text) ?? $"Ошибка создания заказа ({(int)resp.StatusCode}).");
        return JsonSerializer.Deserialize<BuyerOrderResponse>(text, Json) ?? new BuyerOrderResponse();
    }

    /// <summary>Резервирует следующий номер заказа EX-####### (как в WinForms до создания заказа).</summary>
    public async Task<string?> NextGlobalSignAsync()
    {
        EnsureAuth();
        var text = await AuthorizedGetAsync("/api/buyer/global-sign/next", "резервирование номера").ConfigureAwait(false);
        try
        {
            using var doc = JsonDocument.Parse(text);
            return doc.RootElement.TryGetProperty("global_sign", out var v) ? v.GetString() : null;
        }
        catch { return null; }
    }

    /// <summary>Адреса-грузополучатели покупателя.</summary>
    public async Task<List<BuyerLocationDto>> GetBuyerLocationsAsync()
    {
        EnsureAuth();
        var text = await AuthorizedGetAsync("/api/buyer/locations", "загрузку грузополучателей").ConfigureAwait(false);
        try { return JsonSerializer.Deserialize<List<BuyerLocationDto>>(text, Json) ?? new(); }
        catch { return new(); }
    }

    private async Task<string> AuthorizedGetAsync(string path, string op)
    {
        using var req = new HttpRequestMessage(HttpMethod.Get, Url(path));
        req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
        HttpResponseMessage resp;
        try { resp = await _http.SendAsync(req).ConfigureAwait(false); }
        catch (Exception ex) { throw new ApiException($"Не удалось выполнить {op}: {ex.Message}", ex); }

        var text = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
        if (resp.StatusCode == HttpStatusCode.Unauthorized) { _token = null; throw new ApiException("Сессия истекла, войдите снова."); }
        if (!resp.IsSuccessStatusCode) throw new ApiException(TryError(text) ?? $"Ошибка сервера ({(int)resp.StatusCode}) при {op}.");
        return text;
    }

    private void EnsureAuth()
    {
        if (!IsAuthenticated) throw new ApiException("Требуется авторизация.");
    }

    private static string? TryError(string body)
    {
        if (string.IsNullOrWhiteSpace(body)) return null;
        try { return JsonSerializer.Deserialize<ErrorResponse>(body, Json)?.Error; }
        catch { return null; }
    }
}

public sealed class ApiException : Exception
{
    public ApiException(string message, Exception? inner = null) : base(message, inner) { }
}
