using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using log4net;
using log4net.Config;
using System.IO;
using Microsoft.Extensions.Configuration;

namespace SicboSub.StartProcedure
{
    class Program
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Program));

        static async Task Main(string[] args)
        {
            // Load log4net config
            var logRepository = LogManager.GetRepository(System.Reflection.Assembly.GetEntryAssembly());
            XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));

            Console.OutputEncoding = System.Text.Encoding.UTF8; // Hỗ trợ hiển thị tiếng Việt
            log.Info("=== TIẾN TRÌNH TÍNH TOÁN BXH SICBO ===");

            // 1. Cấu hình (Configuration)
            IConfiguration config = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .Build();

            string connectionString = config["Connection"];

            if (string.IsNullOrEmpty(connectionString) || connectionString.Contains("YOUR_DB_HOST"))
            {
                 log.Warn("[CẢNH BÁO] Không đọc được Connection String từ appsettings.json. Vui lòng kiểm tra file config.");
                 // Fallback or explicit error if needed
                 connectionString = "Data Source=YOUR_DB_HOST:1521/YOUR_SERVICE_NAME;User Id=YOUR_USER;Password=YOUR_PASSWORD;";
            }
            else
            {
                 log.Info($"[INFO] Đã load Connection String: {connectionString.Substring(0, 30)}...");
                 // Set current directory base to ensure Oracle driver finds dependencies if needed
                 log.Info($"[INFO] BaseDirectory: {AppContext.BaseDirectory}");
            }

            var service = new RankingService(connectionString, config);
            var exchangeService = new ExchangeService(connectionString, config);

            // 2. Phân tích tham số đầu vào hoặc Chạy mặc định
            // Cách dùng: 
            //   SicboSub.StartProcedure.exe daily
            //   SicboSub.StartProcedure.exe monthly
            //   SicboSub.StartProcedure.exe 2025-01-18 daily

            // 2. Phân tích tham số đầu vào
            bool isDynamicDate = true;
            DateTime targetDate = DateTime.Now.AddDays(-1); 
            string mode = "DAILY";

            if (args.Length > 0)
            {
                if (args[0].ToUpper() == "DAILY") mode = "DAILY";
                else if (args[0].ToUpper() == "MONTHLY") mode = "MONTHLY";
                else if (args[0].ToUpper() == "EXCHANGE") mode = "EXCHANGE";
                else if (DateTime.TryParse(args[0], out DateTime parsedDate)) 
                {
                    targetDate = parsedDate;
                    isDynamicDate = false;
                }

                if (args.Length > 1)
                {
                   if (args[1].ToUpper() == "DAILY") mode = "DAILY";
                   else if (args[1].ToUpper() == "MONTHLY") mode = "MONTHLY";
                   else if (args[1].ToUpper() == "EXCHANGE") mode = "EXCHANGE";
                }
            }

            log.Info($"Chế độ chạy: {mode}");
            if (!isDynamicDate) log.Info($"Ngày mục tiêu (Fixed): {targetDate:yyyy-MM-dd}");
            else log.Info($"Ngày mục tiêu (Dynamic): {targetDate:yyyy-MM-dd} (Yesterday)");

            // 3. Thực thi
            log.Info("Press Ctrl+C to stop...");
            
            // Create a cancellation token source to handle manual stop
            var cts = new CancellationTokenSource();
            Console.CancelKeyPress += (s, e) =>
            {
                e.Cancel = true;
                cts.Cancel();
                log.Info("Stop request received...");
            };

            int lastMonthlyRunDay = -1;

            while (!cts.Token.IsCancellationRequested)
            {
                // Update dynamic date
                if (isDynamicDate) targetDate = DateTime.Now.AddDays(-1);

                try 
                {
                    // 3. Thực thi
                    if (mode == "DAILY")
                    {
                        await service.ExecuteDailyRankingAsync(targetDate);

                        // AUTO MONTHLY TRIGGER (Only in Dynamic Mode)
                        // Nếu là ngày mùng 1, tự động chạy thêm Monthly cho ngày hôm qua (tức là cuối tháng trước)
                        if (isDynamicDate && DateTime.Now.Day == 1)
                        {
                            if (lastMonthlyRunDay != DateTime.Now.Day)
                            {
                                log.Info("[AUTO] Phát hiện ngày mùng 1 -> Kích hoạt chạy BXH Tháng (Monthly Ranking)...");
                                await service.ExecuteMonthlyRankingAsync(targetDate);
                                lastMonthlyRunDay = DateTime.Now.Day;
                            }
                        }
                        else
                        {
                             if (DateTime.Now.Day != 1) lastMonthlyRunDay = -1;
                        }

                        // Run Exchange Processing specifically in Daily mode (common use case)
                         await exchangeService.ExecuteExchangeProcessingAsync();
                    }
                    else if (mode == "MONTHLY")
                    {
                         // Đối với chạy Tháng, Procedure sẽ lấy ngày truyền vào để xác định tháng.
                         // VD: 14/01/2026 -> Sẽ tính cho Tháng 1/2026.
                         // Nếu muốn tính tháng trước, cần đảm bảo targetDate thuộc về tháng trước.
                        await service.ExecuteMonthlyRankingAsync(targetDate);
                    }
                    else if (mode == "EXCHANGE")
                    {
                        await exchangeService.ExecuteExchangeProcessingAsync();
                    }

                    // Wait 5 seconds before next run
                    log.Info("Waiting 5s before next run...");
                    await Task.Delay(5000, cts.Token);
                }
                catch (TaskCanceledException)
                {
                    break;
                }
                catch (Exception ex)
                {
                     log.Error("Unexpected error in main loop:", ex);
                     await Task.Delay(5000); // Wait on error too
                }
            }

            log.Info("Program stopped.");
        }
    }
}
