using System.Reflection;
using Predictalytics.WinFormsHost.Services;
using Serilog;

namespace Predictalytics.WinFormsHost;

public partial class MainForm : Form
{
    private EmbeddedWebServer? _webServer;
    private CancellationTokenSource? _workerCts;
    private bool _workerRunning;
    private bool _webServerRunning;
    private AppSettings _settings = null!;

    /// <summary>Exposes the terminal RichTextBox for the Serilog sink.</summary>
    public RichTextBox Terminal => rtb_terminal;

    public MainForm()
    {
        InitializeComponent();
        this.Text = "Predictalytics Analytics — Backend Server";
        rtb_terminal.BackColor = System.Drawing.Color.FromArgb(15, 15, 20);
        rtb_terminal.ForeColor = System.Drawing.Color.FromArgb(180, 180, 180);
        rtb_terminal.Font = new Font("Cascadia Code", 9.5f, FontStyle.Regular);
        rtb_terminal.ReadOnly = true;
    }

    /// <summary>
    /// Called after Serilog is configured. Initializes the embedded web server.
    /// </summary>
    public void Initialize()
    {
        _settings = AppSettings.Load();
        pg_settings.SelectedObject = _settings;
        pg_settings.PropertyValueChanged += (s, e) => {
            _settings.Save();
            if (_webServer != null)
            {
                _webServer.ConnectionString = _settings.ConnectionString;
                _webServer.DbConnectionDebug = _settings.DbConnectionDebug;
                _webServer.EgressChannelsText = _settings.EgressChannelsText;
            }
        };

        _webServer = new EmbeddedWebServer();
        _webServer.ConnectionString = _settings.ConnectionString;
        _webServer.DbConnectionDebug = _settings.DbConnectionDebug;
        _webServer.EgressChannelsText = _settings.EgressChannelsText;
        
        // Build Version (Date of compilation/file creation)
        try {
            var buildDate = new FileInfo(this.GetType().Assembly.Location).LastWriteTime;
            label_buildVersion.Text = $"Build: {buildDate:yyyy-MM-dd HH:mm:ss}";
        } catch {
            label_buildVersion.Text = "Build: Unknown";
        }

        UpdateStatusBar();

        // Wire up button events
        btn_serverstart.Click += Btn_serverstart_Click;
        btn_localWebserver.Click += Btn_localWebserver_Click;

        Log.Information("MainForm initialized. Ready.");
        Log.Information("Press 'Start Server' to begin polling & discovery.");
        Log.Information("Press 'Start Local Webserver' to launch the WebUI on http://localhost:{Port}", _settings.WebserverPort);

        _ = UpdateDbSizeAsync();
        var dbSizeTimer = new System.Windows.Forms.Timer { Interval = 6 * 60 * 60 * 1000 };
        dbSizeTimer.Tick += async (s, e) => await UpdateDbSizeAsync();
        dbSizeTimer.Start();
    }

    private async void Btn_serverstart_Click(object? sender, EventArgs e)
    {
        if (!_workerRunning)
        {
            // Start workers
            _workerCts = new CancellationTokenSource();
            _workerRunning = true;
            btn_serverstart.Text = "⏹ Stop Server";
            Log.Information("🚀 Starting background workers...");
            
            try
            {
                _webServer!.ConnectionString = _settings.ConnectionString;
                _webServer!.DbConnectionDebug = _settings.DbConnectionDebug;
                _webServer!.EgressChannelsText = _settings.EgressChannelsText;
                await _webServer!.StartWorkersAsync(_workerCts.Token);
            }
            catch (OperationCanceledException) { }
            catch (Exception ex) { Log.Error(ex, "Worker error"); }
        }
        else
        {
            // Stop workers
            Log.Information("⏹ Stopping background workers...");
            _workerCts?.Cancel();
            _workerRunning = false;
            btn_serverstart.Text = "▶ Start Server";
            Log.Information("Workers stopped.");
        }
        UpdateStatusBar();
    }

    private async void Btn_localWebserver_Click(object? sender, EventArgs e)
    {
        if (!_webServerRunning)
        {
            try
            {
                Log.Information("🌐 Starting embedded Kestrel webserver on http://localhost:{Port}...", _settings.WebserverPort);
                await _webServer!.StartWebServerAsync(_settings.WebserverPort);
                _webServerRunning = true;
                btn_localWebserver.Text = "⏹ Stop Webserver";
                Log.Information("✅ WebUI available at http://localhost:{Port}", _settings.WebserverPort);
                Log.Information("📄 Swagger API docs at http://localhost:{Port}/swagger", _settings.WebserverPort);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Failed to start webserver");
                _webServerRunning = false;
            }
        }
        else
        {
            Log.Information("⏹ Stopping webserver...");
            await _webServer!.StopWebServerAsync();
            _webServerRunning = false;
            btn_localWebserver.Text = "▶ Start Webserver";
            Log.Information("Webserver stopped.");
        }
        UpdateStatusBar();
    }

    private void UpdateStatusBar()
    {
        var workerStatus = _workerRunning ? "[RUNNING] Workers" : "[STOPPED] Workers";
        var serverStatus = _webServerRunning ? $"[RUNNING] Webserver :{_settings.WebserverPort}" : "[STOPPED] Webserver";
        this.Text = $"Predictalytics Analytics — {workerStatus} | {serverStatus}";
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        _workerCts?.Cancel();
        _webServer?.StopWebServerAsync().GetAwaiter().GetResult();
        base.OnFormClosing(e);
    }

    private void btn_openbrowser_Click(object sender, EventArgs e)
    {
        try
        {
            System.Diagnostics.Process.Start("explorer.exe", $"\"http://localhost:{_settings.WebserverPort}\"");
        }
        catch (Exception ex)
        {
            Serilog.Log.Error(ex, "Fehler beim Öffnen des Browsers");
            MessageBox.Show("Browser konnte nicht gestartet werden.", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    private void btn_logfolder_Click(object sender, EventArgs e)
    {
        try
        {
            var logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
            if (Directory.Exists(logPath))
                System.Diagnostics.Process.Start("explorer.exe", logPath);
            else
                System.Diagnostics.Process.Start("explorer.exe", Environment.CurrentDirectory);
        }
        catch (Exception ex)
        {
            Serilog.Log.Error(ex, "Fehler beim Öffnen des Log-Ordners");
        }
    }

    private async void syncMarketsaToolStripMenuItem_Click(object? sender, EventArgs e)
    {
        if (_workerRunning)
        {
            MessageBox.Show("Market sync cannot be started while background workers are running.",
                "Workers Busy", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            return;
        }

        try
        {
            btn_syncmarkets.Enabled = false;
            Log.Information("Manual market sync triggered...");
            
            // Use a temporary CTS for this operation
            using var cts = new CancellationTokenSource();
            await _webServer!.RunSingleMarketSyncAsync(cts.Token);
            
            Log.Information("Manual market sync completed successfully.");
            MessageBox.Show("Market sync completed.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        catch (Exception ex)
        {
            Log.Error(ex, "Manual market sync failed");
            MessageBox.Show($"Error syncing markets: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        finally
        {
            btn_syncmarkets.Enabled = true;
        }
    }

    private async void btn_dbUpdate_Click(object? sender, EventArgs e)
    {
        if (_workerRunning)
        {
            MessageBox.Show("Database update cannot be run while background workers are running.",
                "Workers Busy", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            return;
        }

        try
        {
            btn_dbUpdate.Enabled = false;
            Log.Information("Manual database update triggered...");
            await _webServer!.UpdateDatabaseAsync();
            Log.Information("Database updated successfully.");
            MessageBox.Show("Database update completed successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        catch (Exception ex)
        {
            Log.Error(ex, "Manual database update failed");
            MessageBox.Show($"Database update failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        finally
        {
            btn_dbUpdate.Enabled = true;
        }
    }

    private async void btn_recalcAll_Click(object? sender, EventArgs e)
    {
        if (_workerRunning)
        {
            MessageBox.Show("Recalculation cannot be started while background workers are running. Stop the server first.",
                "Workers Busy", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            return;
        }

        var confirm = MessageBox.Show(
            "This deletes all DERIVED analytics data (positions, daily snapshots, category stats) " +
            "and marks every trader for full recalculation.\n\n" +
            "Raw trades and markets are NOT touched.\n\n" +
            "After this, start the server: the analytics worker rebuilds every trader with the current " +
            "engine (runs in the background, can take several hours for large trader counts).\n\nContinue?",
            "Recalculate All Traders", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
        if (confirm != DialogResult.Yes) return;

        try
        {
            btn_recalcAll.Enabled = false;
            Log.Information("Manual full recalculation reset triggered...");

            using var cts = new CancellationTokenSource();
            var summary = await _webServer!.RunRecalculateAllTradersAsync(cts.Token);

            MessageBox.Show($"Reset complete:\n\n{summary}\n\nNow start the server to rebuild the analytics.",
                "Recalculate All Traders", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        catch (Exception ex)
        {
            Log.Error(ex, "Full recalculation reset failed");
            MessageBox.Show($"Recalculation reset failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        finally
        {
            btn_recalcAll.Enabled = true;
        }
    }

    private async Task UpdateDbSizeAsync()
    {
        try
        {
            // Build the connection string
            var csBuilder = new MySqlConnector.MySqlConnectionStringBuilder(_settings.ConnectionString);
            if (string.IsNullOrWhiteSpace(csBuilder.Database)) 
                return; // Not ready or valid yet
                
            using var conn = new MySqlConnector.MySqlConnection(_settings.ConnectionString);
            await conn.OpenAsync();
            using var cmd = conn.CreateCommand();
            cmd.CommandText = "SELECT SUM(data_length + index_length) / 1024 / 1024 FROM information_schema.tables WHERE table_schema = DATABASE();";
            
            var result = await cmd.ExecuteScalarAsync();
            if (result != DBNull.Value && result != null)
            {
                var sizeMb = Convert.ToDouble(result);
                this.Invoke(() => label_dbSize.Text = $"DB Size: {sizeMb:F2} MB");
            }
        }
        catch (Exception ex)
        {
            this.Invoke(() => label_dbSize.Text = "DB Size: Error");
            Log.Debug(ex, "Failed to fetch DB size for status bar");
        }
    }
}
