using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;
using Altob.NtuInvoiceGateway.Models;
using System.Text;
using System.Text.Json;
using System.Linq;

namespace Altob.NtuInvoiceGateway.Pages;

[IgnoreAntiforgeryToken]  // 允許外部系統 POST JSON 請求
public class InvoiceModel : PageModel
{
    private readonly ILogger<InvoiceModel> _logger;
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly CompanyInfo _companyInfo;
    private readonly InvoiceApiOptions _invoiceApiOptions;
    private const string ServiceName = "NtuInvoiceGateway";

    public InvoiceModel(
        ILogger<InvoiceModel> logger,
        IHttpClientFactory httpClientFactory,
        IOptions<CompanyInfo> companyInfo,
        IOptions<InvoiceApiOptions> invoiceApiOptions)
    {
        _logger = logger;
        _httpClientFactory = httpClientFactory;
        _companyInfo = companyInfo.Value;
        _invoiceApiOptions = invoiceApiOptions.Value;
    }

    [BindProperty]
    public InvoiceRequest InvoiceData { get; set; } = new();

    public string? ErrorMessage { get; set; }
    [TempData]
    public string? SuccessMessage { get; set; }
    public string CompanyName => _companyInfo.Name;
    public string CompanyTaxId => _companyInfo.TaxId;

    // 顯示用的發票資訊（唯讀）
    public string DisplayTransDateTime { get; set; } = string.Empty;
    public string DisplayTransAmount { get; set; } = string.Empty;

    public void OnGet()
    {
        RestoreDisplayValuesFromTempData();
        // GET 方法保留為空，主要接收方式改為 POST JSON
    }

    public async Task<IActionResult> OnPostAsync()
    {
        NormalizeInvoiceData();
        var actionName = nameof(OnPostAsync);
        _logger.LogInformation("{ServiceName} - {ActionName} received JSON redirect payload {@InvoiceData}",
            ServiceName, actionName, InvoiceData);
        // 檢查是否為 JSON 請求（外部系統轉頁）
        if (Request.ContentType?.Contains("application/json") == true)
        {
            try
            {
                // 從 Request Body 讀取 JSON 資料
                using var reader = new StreamReader(Request.Body);
                var jsonContent = await reader.ReadToEndAsync();
                _logger.LogInformation("{ServiceName} - {ActionName} JSON payload content: {JsonPayload}", ServiceName, actionName, jsonContent);

                var jsonData = JsonSerializer.Deserialize<InvoiceRequest>(jsonContent, new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    PropertyNameCaseInsensitive = true
                });

                if (jsonData != null)
                {
                    InvoiceData = jsonData;
                    NormalizeInvoiceData();
                    DisplayTransDateTime = InvoiceData.TransDateTime;
                    DisplayTransAmount = InvoiceData.TransAmount;
                    ModelState.Clear(); // ensure Razor uses the JSON payload values

                    _logger.LogInformation("{ServiceName} - {ActionName} received redirect for OrderID: {OrderID}", ServiceName, actionName, InvoiceData.OrderID);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "{ServiceName} - {ActionName} error parsing JSON request", ServiceName, actionName);
                ErrorMessage = "接收轉頁資料時發生錯誤";
            }
        }
        // 顯示表單讓用戶填寫
        return Page();
    }
    
    public async Task<IActionResult> OnPostToEndPointAsync()
    {
        NormalizeInvoiceData();
        // 處理表單提交
        // 保留發票資訊顯示
        DisplayTransDateTime = InvoiceData.TransDateTime;
        DisplayTransAmount = InvoiceData.TransAmount;
        var actionName = nameof(OnPostToEndPointAsync);
        _logger.LogInformation("{ServiceName} - {ActionName} received invoice submission payload {@InvoiceData}",
            ServiceName, actionName, InvoiceData);

        // 判斷是否為初始轉頁（三個選項都沒填寫）
        bool isInitialRedirect = string.IsNullOrEmpty(InvoiceData.Email) &&
                                 string.IsNullOrEmpty(InvoiceData.CarrierID) &&
                                 string.IsNullOrEmpty(InvoiceData.BuyerIdentifier) &&
                                 string.IsNullOrEmpty(InvoiceData.LoveCode);

        // 如果是初始轉頁，直接顯示表單讓用戶填寫
        if (isInitialRedirect)
        {
            return Page();
        }

        if (!ModelState.IsValid)
        {
            var invalidFields = ModelState
                .Where(entry => entry.Value?.Errors.Count > 0)
                .Select(entry =>
                {
                    var fieldName = string.IsNullOrEmpty(entry.Key) ? "表單" : entry.Key;
                    var messages = string.Join("、", entry.Value!.Errors.Select(e => e.ErrorMessage));
                    return $"{fieldName}：{messages}";
                });

            ErrorMessage = "資料驗證失敗，請檢查欄位輸入";
            _logger.LogWarning("{ServiceName} - {ActionName} validation failed: {ValidationErrors}", ServiceName, actionName, string.Join(" | ", invalidFields));
            return Page();
        }

        // 驗證 Email, CarrierID, BuyerIdentifier 至少填寫一個
        int filledCount = 0;
        if (!string.IsNullOrEmpty(InvoiceData.Email)) filledCount++;
        if (!string.IsNullOrEmpty(InvoiceData.CarrierID)) filledCount++;
        if (!string.IsNullOrEmpty(InvoiceData.BuyerIdentifier)) filledCount++;
        if (!string.IsNullOrEmpty(InvoiceData.LoveCode)) filledCount++;

        if (filledCount == 0)
        {
            ErrorMessage = "Email、手機條碼、購買者統編至少需填寫一個";
            return Page();
        }

        if (string.IsNullOrWhiteSpace(_invoiceApiOptions.Endpoint))
        {
            ErrorMessage = "未設定外部發票 API 的位址";
            _logger.LogError("{ServiceName} - {ActionName} Invoice API endpoint is not configured", ServiceName, actionName);
            return Page();
        }

        try
        {
            // 呼叫 TODO API（這裡使用規格中的範例 API）
            // http://192.168.110.72:22055/api/Intella/invoiceInfo
            // {
            //     "identifier": "12345678",
            //     "transDateTime": "2026/01/08 12:00:00",
            //     "transAmount": "30",
            //     "deviceID": "test",
            //     "locationID": "1",
            //     "carPlateNum": "ABC1235",
            //     "orderID": "260109_1",
            //     "email": "",
            //     "carrierID": "/ab12345",
            //     "buyerIdentifier": "",
            //     "taxType": "1",
            //     "loveCode": ""
            // }
            var httpClient = _httpClientFactory.CreateClient();
            var requestBody = JsonSerializer.Serialize(InvoiceData, new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            });
            _logger.LogInformation("{ServiceName} - {ActionName} sending API payload: {RequestBody}",
                ServiceName, actionName, requestBody);

            var content = new StringContent(requestBody, Encoding.UTF8, "application/json");

            var response = await httpClient.PostAsync(_invoiceApiOptions.Endpoint, content);

            var responseContent = await response.Content.ReadAsStringAsync();
            _logger.LogInformation("{ServiceName} - {ActionName} received API response status {StatusCode} body: {ResponseBody}",
                ServiceName, actionName, response.StatusCode, responseContent);
            var apiResponse = JsonSerializer.Deserialize<InvoiceResponse>(responseContent, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            });

            if (!response.IsSuccessStatusCode)
            {
                ErrorMessage = $"提交失敗：{apiResponse?.msg ?? response.StatusCode.ToString()}";
                _logger.LogWarning("{ServiceName} - {ActionName} submission failed with HTTP {StatusCode} for OrderID: {OrderID}",
                    ServiceName, actionName, response.StatusCode, InvoiceData.OrderID);
                return Page();
            }

            if (apiResponse?.msgCode == "0000")
            {
                SuccessMessage = "發票資訊提交成功！";
                TempData[nameof(DisplayTransDateTime)] = DisplayTransDateTime;
                TempData[nameof(DisplayTransAmount)] = DisplayTransAmount;
                _logger.LogInformation("{ServiceName} - {ActionName} submitted successfully for OrderID: {OrderID}",
                    ServiceName, actionName, InvoiceData.OrderID);
                return RedirectToPage();
            }
            else
            {
                ErrorMessage = $"提交失敗：{apiResponse?.msg ?? "未知錯誤"}";
                _logger.LogWarning("{ServiceName} - {ActionName} submission failed: {Message}", ServiceName, actionName, apiResponse?.msg);
            }
        }
        catch (Exception ex)
        {
#if DEBUG
            ErrorMessage = $"系統錯誤：{ex.Message}";
#else
            ErrorMessage = $"系統錯誤";
#endif
            _logger.LogError(ex, "{ServiceName} - {ActionName} error submitting invoice for OrderID: {OrderID}",
                ServiceName, actionName, InvoiceData.OrderID);
        }

        return Page();
    }

    private void NormalizeInvoiceData()
    {
        InvoiceData ??= new InvoiceRequest();

        InvoiceData.Identifier = InvoiceData.Identifier ?? string.Empty;
        InvoiceData.TransDateTime = InvoiceData.TransDateTime ?? string.Empty;
        InvoiceData.TransAmount = InvoiceData.TransAmount ?? string.Empty;
        InvoiceData.DeviceID = InvoiceData.DeviceID ?? string.Empty;
        InvoiceData.LocationID = InvoiceData.LocationID ?? string.Empty;
        InvoiceData.CarPlateNum = InvoiceData.CarPlateNum ?? string.Empty;
        InvoiceData.OrderID = InvoiceData.OrderID ?? string.Empty;
        InvoiceData.TaxType = InvoiceData.TaxType ?? string.Empty;
    }

    private void RestoreDisplayValuesFromTempData()
    {
        if (TempData.TryGetValue(nameof(DisplayTransDateTime), out var transDateObj) &&
            transDateObj is string transDate)
        {
            DisplayTransDateTime = transDate;
        }

        if (TempData.TryGetValue(nameof(DisplayTransAmount), out var amountObj) &&
            amountObj is string amount)
        {
            DisplayTransAmount = amount;
        }
    }
}
