using Microsoft.Extensions.Options;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace StockFin
{
    public sealed class FinnhubOptions
    {
        public const string SectionName = "Finnhub";

        public string ApiKey { get; set; } = string.Empty;
    }

    public interface IFinnhubClient
    {
        Task<FinnhubQuote?> GetQuoteAsync(
            string symbol,
            CancellationToken cancellationToken = default);
    }

    public sealed class FinnhubClient : IFinnhubClient
    {
        private readonly HttpClient _httpClient;
        private readonly FinnhubOptions _options;
        private readonly ILogger<FinnhubClient> _logger;

        public FinnhubClient(
            HttpClient httpClient,
            IOptions<FinnhubOptions> options,
            ILogger<FinnhubClient> logger)
        {
            _httpClient = httpClient;
            _options = options.Value;
            _logger = logger;
        }

        public async Task<FinnhubQuote?> GetQuoteAsync(
            string symbol,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrWhiteSpace(symbol))
            {
                _logger.LogWarning("GetQuoteAsync called with empty symbol.");
                return null;
            }

            if (string.IsNullOrWhiteSpace(_options.ApiKey))
            {
                _logger.LogWarning("Finnhub API key is not configured.");
                return null;
            }

            try
            {
                var url = $"quote?symbol={Uri.EscapeDataString(symbol)}&token={_options.ApiKey}";

                var response = await _httpClient.GetAsync(url, cancellationToken);

                if (!response.IsSuccessStatusCode)
                {
                    _logger.LogWarning(
                        "Finnhub returned {StatusCode} for symbol {Symbol}.",
                        (int)response.StatusCode, symbol);
                    return null;
                }

                var quote = await response.Content.ReadFromJsonAsync<FinnhubQuote>(cancellationToken);

                if (quote == null || quote.CurrentPrice == 0)
                {
                    _logger.LogWarning("Finnhub returned no data for symbol {Symbol}.", symbol);
                    return null;
                }

                return quote;
            }
            catch (HttpRequestException ex)
            {
                _logger.LogError(ex, "Network error fetching Finnhub quote for {Symbol}.", symbol);
                return null;
            }
            catch (JsonException ex)
            {
                _logger.LogError(ex, "JSON deserialization error for Finnhub quote {Symbol}.", symbol);
                return null;
            }
            catch (TaskCanceledException ex)
            {
                _logger.LogError(ex, "Finnhub request timed out or was cancelled for {Symbol}.", symbol);
                return null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Unexpected error fetching Finnhub quote for {Symbol}.", symbol);
                return null;
            }
        }
    }

    public sealed class FinnhubQuote
    {
        [JsonPropertyName("c")]
        public double CurrentPrice { get; set; }

        [JsonPropertyName("d")]
        public decimal Change { get; set; }

        [JsonPropertyName("dp")]
        public decimal PercentChange { get; set; }

        [JsonPropertyName("h")]
        public decimal High { get; set; }

        [JsonPropertyName("l")]
        public decimal Low { get; set; }

        [JsonPropertyName("o")]
        public decimal Open { get; set; }

        [JsonPropertyName("pc")]
        public decimal PreviousClose { get; set; }

        [JsonPropertyName("t")]
        public long Timestamp { get; set; }
    }
}
