using Microsoft.AspNetCore.Mvc;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;

namespace eSPJ.Controllers.SpjDriverUpstController
{
    [Route("upst/submit")]
    public class SubmitController : Controller
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly IConfiguration _configuration;
        private readonly IWebHostEnvironment _env;

        public SubmitController(
            IHttpClientFactory httpClientFactory,
            IConfiguration configuration,
            IWebHostEnvironment env)
        {
            _httpClientFactory = httpClientFactory;
            _configuration = configuration;
            _env = env;
        }

        [HttpGet("")]
        public IActionResult Index()
        {
            return View("~/Views/Admin/Transport/SpjDriverUpst/Submit/Index.cshtml");
        }

        [HttpGet("struk")]
        public IActionResult Struk()
        {
            return View("~/Views/Admin/Transport/SpjDriverUpst/Submit/Struk.cshtml");
        }

        [HttpPost("ocr-struk")]
        [IgnoreAntiforgeryToken]
        public async Task<IActionResult> OcrStruk(IFormFile? Foto)
        {
            if (Foto == null || Foto.Length == 0)
                return BadRequest(new { success = false, message = "Foto tidak ditemukan." });

            if (Foto.Length > 10 * 1024 * 1024)
                return BadRequest(new { success = false, message = "Ukuran foto terlalu besar. Maksimal 10MB." });

            var apiKey = _configuration["OpenRouter:OCRkey"];
            if (string.IsNullOrWhiteSpace(apiKey))
                return StatusCode(500, new { success = false, message = "OpenRouter API key belum diset." });

            byte[] fileBytes;
            await using (var ms = new MemoryStream())
            {
                await Foto.CopyToAsync(ms);
                fileBytes = ms.ToArray();
            }

            var mimeType = string.IsNullOrWhiteSpace(Foto.ContentType) ? "image/jpeg" : Foto.ContentType;
            var base64 = Convert.ToBase64String(fileBytes);
            var dataUrl = $"data:{mimeType};base64,{base64}";

            var payload = new
            {
                model = "google/gemini-2.5-flash-image",
                temperature = 0,
                messages = new object[]
                {
                    new
                    {
                        role = "user",
                        content = new object[]
                        {
                            new
                            {
                                type = "text",
                                text = @"Baca data dari foto struk timbang kendaraan ini. Ekstrak semua data yang tersedia ke dalam format JSON berikut:
                                {
                                ""nomorStruk"": ""<nomor struk tanpa prefix, contoh: 8001441>"",
                                ""nomorPolisi"": ""<nomor polisi kendaraan, contoh: B 9125 PJA>"",
                                ""penugasan"": ""<area penugasan, contoh: JAKARTA BARAT>"",
                                ""waktuMasuk"": ""<waktu masuk format YYYY-MM-DD, HH:MM:SS>"",
                                ""waktuKeluar"": ""<waktu keluar format YYYY-MM-DD, HH:MM:SS>"",
                                ""beratMasuk"": <berat masuk dalam kg sebagai angka integer tanpa desimal>,
                                ""beratKeluar"": <berat keluar dalam kg sebagai angka integer tanpa desimal>,
                                ""beratNett"": <berat netto dalam kg sebagai angka integer tanpa desimal>
                                }

                                Catatan penting:
                                - nomorStruk: ambil angka utama saja, abaikan prefix bulan seperti '03_' atau '03 '
                                - waktu: konversi ke format YYYY-MM-DD, HH:MM:SS (contoh: 2025-08-04, 08:13:51)
                                - berat: hanya angka integer tanpa satuan 'kg'
                                - Jika data tidak ada atau tidak terbaca, isi dengan null
                                - Kembalikan HANYA JSON valid tanpa penjelasan atau markdown code block"
                            },
                            new
                            {
                                type = "image_url",
                                image_url = new { url = dataUrl }
                            }
                        }
                    }
                }
            };

            var json = JsonSerializer.Serialize(payload);
            var request = new HttpRequestMessage(HttpMethod.Post, "https://openrouter.ai/api/v1/chat/completions");
            request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {apiKey}");
            request.Headers.TryAddWithoutValidation("Accept", "application/json");
            request.Headers.TryAddWithoutValidation("HTTP-Referer", "https://pesapakawan.dinaslhdki.id");
            request.Headers.TryAddWithoutValidation("X-Title", "eSPJ OCR Struk");
            request.Content = new StringContent(json, Encoding.UTF8, "application/json");

            var client = _httpClientFactory.CreateClient();
            using var response = await client.SendAsync(request);
            var responseText = await response.Content.ReadAsStringAsync();

            if (!response.IsSuccessStatusCode)
            {
                return StatusCode((int)response.StatusCode, new
                {
                    success = false,
                    message = "OpenRouter request gagal.",
                    detail = responseText
                });
            }

            using var doc = JsonDocument.Parse(responseText);
            var content = doc.RootElement
                .GetProperty("choices")[0]
                .GetProperty("message")
                .GetProperty("content")
                .GetString() ?? "";

            var jsonMatch = Regex.Match(content, @"\{[\s\S]*\}");
            if (!jsonMatch.Success)
                return Ok(new { success = false, message = "AI tidak mengembalikan data valid.", raw = content });

            try
            {
                using var dataDoc = JsonDocument.Parse(jsonMatch.Value);
                var root = dataDoc.RootElement;
                return Ok(new
                {
                    success = true,
                    data = new
                    {
                        nomorStruk = GetStringValue(root, "nomorStruk"),
                        nomorPolisi = GetStringValue(root, "nomorPolisi"),
                        penugasan = GetStringValue(root, "penugasan"),
                        waktuMasuk = GetStringValue(root, "waktuMasuk"),
                        waktuKeluar = GetStringValue(root, "waktuKeluar"),
                        beratMasuk = GetIntValue(root, "beratMasuk"),
                        beratKeluar = GetIntValue(root, "beratKeluar"),
                        beratNett = GetIntValue(root, "beratNett")
                    },
                    raw = content
                });
            }
            catch
            {
                return Ok(new { success = false, message = "Gagal memproses respons AI.", raw = content });
            }
        }

        [HttpPost("struk")]
        public async Task<IActionResult> ProcessStruk(
            string? NomorStruk,
            string? NomorPolisi,
            string? Penugasan,
            string? WaktuMasuk,
            string? WaktuKeluar,
            int? BeratMasuk,
            int? BeratKeluar,
            int? BeratNett,
            string? Timbang,
            IFormFile? FotoStruk)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(NomorStruk))
                {
                    TempData["Error"] = "Nomor struk wajib diisi.";
                    return RedirectToAction("Struk");
                }

                if (!Regex.IsMatch(NomorStruk, @"^\d{3,}$"))
                {
                    TempData["Error"] = "Format nomor struk tidak valid. Harus berupa angka minimal 3 digit.";
                    return RedirectToAction("Struk");
                }

                if (string.IsNullOrWhiteSpace(NomorPolisi))
                {
                    TempData["Error"] = "Nomor polisi wajib diisi.";
                    return RedirectToAction("Struk");
                }

                if (string.IsNullOrWhiteSpace(Penugasan))
                {
                    TempData["Error"] = "Penugasan wajib diisi.";
                    return RedirectToAction("Struk");
                }

                if (string.IsNullOrWhiteSpace(WaktuMasuk))
                {
                    TempData["Error"] = "Waktu masuk wajib diisi.";
                    return RedirectToAction("Struk");
                }

                if (string.IsNullOrWhiteSpace(WaktuKeluar))
                {
                    TempData["Error"] = "Waktu keluar wajib diisi.";
                    return RedirectToAction("Struk");
                }

                if (!BeratMasuk.HasValue || BeratMasuk <= 0)
                {
                    TempData["Error"] = "Berat masuk wajib diisi.";
                    return RedirectToAction("Struk");
                }

                if (!BeratKeluar.HasValue || BeratKeluar <= 0)
                {
                    TempData["Error"] = "Berat keluar wajib diisi.";
                    return RedirectToAction("Struk");
                }

                if (!BeratNett.HasValue || BeratNett <= 0)
                {
                    TempData["Error"] = "Berat nett wajib diisi.";
                    return RedirectToAction("Struk");
                }

                if (FotoStruk == null || FotoStruk.Length == 0)
                {
                    TempData["Error"] = "Foto struk wajib dilampirkan.";
                    return RedirectToAction("Struk");
                }

                string? fotoStrukUrl = null;
                if (FotoStruk != null && FotoStruk.Length > 0)
                {
                    var datePart = DateTime.Now.ToString("yyyy-MM-dd");
                    var uploadPath = Path.Combine(_env.ContentRootPath, "uploads", "struk", datePart);
                    if (!Directory.Exists(uploadPath))
                        Directory.CreateDirectory(uploadPath);

                    var ext = Path.GetExtension(FotoStruk.FileName).ToLowerInvariant();
                    if (string.IsNullOrEmpty(ext)) ext = ".jpg";
                    var fileName = $"struk_{NomorStruk}_{Guid.NewGuid():N}{ext}";
                    var filePath = Path.Combine(uploadPath, fileName);
                    await using var stream = new FileStream(filePath, FileMode.Create);
                    await FotoStruk.CopyToAsync(stream);
                    fotoStrukUrl = $"/uploads/struk/{datePart}/{fileName}";
                }

                var timbangLabel = Timbang == "RDF" ? "Timbangan RDF" : "Timbangan TPA";
                TempData["Success"] = $"Struk berhasil disubmit! No: {NomorStruk}, {timbangLabel}, Nett: {BeratNett!.Value} kg";
                return RedirectToAction("Index", "Home");
            }
            catch (Exception)
            {
                TempData["Error"] = "Terjadi kesalahan saat memproses struk. Silakan coba lagi.";
                return RedirectToAction("Struk");
            }
        }

        private static string? GetStringValue(JsonElement root, string key)
        {
            if (root.TryGetProperty(key, out var prop) && prop.ValueKind == JsonValueKind.String)
                return prop.GetString();
            return null;
        }

        private static int? GetIntValue(JsonElement root, string key)
        {
            if (root.TryGetProperty(key, out var prop))
            {
                if (prop.ValueKind == JsonValueKind.Number && prop.TryGetInt32(out var val))
                    return val;
                if (prop.ValueKind == JsonValueKind.String && int.TryParse(prop.GetString(), out var strVal))
                    return strVal;
            }
            return null;
        }
    }
}
