using Microsoft.Web.WebView2.Core;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace HMIWeb
{
    public partial class MainForm : Form
    {
        private Microsoft.Web.WebView2.WinForms.WebView2 webView;
        private Timer plcTimer;
        private WebSocketServer _wsServer;

        // Machine State (Simulated PLC Memory)
        private double currX = 0, currY = 0, currZ = 0;
        private double targetX = 0, targetY = 0, targetZ = 0;
        private bool[] inputs = new bool[32];
        private bool[] outputs = new bool[32];
        private string systemState = "IDLE";
        public MainForm()
        {
            InitializeComponent();
            InitializeWebView();

            // Start WebSocket Server for HMR/Dev
            try
            {
                _wsServer = new WebSocketServer("http://localhost:8081/", this);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to start WebSocket Server (Port 8081). Run as Admin or allow port.\n" + ex.Message);
            }

            // Set default inputs (Pressure OK, Estop OK)
            inputs[4] = true;
            inputs[6] = true;
        }

        private async void InitializeWebView()
        {
            // 1. Setup Virtual Host (http://hmi.local) pointing to frontend/dist folder
            // Navigate up from bin/Debug/ to project root, then to frontend/dist
            string projectRoot = Path.GetFullPath(Path.Combine(Application.StartupPath, @"..\..\..\.."));
            string wwwroot = Path.Combine(projectRoot, @"frontend\dist");

            this.Text = $"HMI Host - {wwwroot}";

            webView = new Microsoft.Web.WebView2.WinForms.WebView2();
            webView.Dock = DockStyle.Fill;
            this.Controls.Add(webView);

            await webView.EnsureCoreWebView2Async();
            
            if (!Directory.Exists(wwwroot))
            {
                MessageBox.Show($"Could not find frontend build at:\n{wwwroot}\n\nPlease run 'npm run build' in the frontend folder.", "Frontend Not Found", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                // Fallback to local wwwroot if needed, or just allow it to fail gracefully
                Directory.CreateDirectory(wwwroot); 
            }

            webView.CoreWebView2.SetVirtualHostNameToFolderMapping(
                "hmi.local",
                wwwroot,
                CoreWebView2HostResourceAccessKind.Allow
            );

            // 2. Inject Native Object
            webView.CoreWebView2.AddHostObjectToScript("machine", new MachineBridge(this));

            // 3. Load UI
            //webView.Source = new Uri("http://hmi.local/index.html");

            // Disable default browser keys (F5, F12 etc) if needed for kiosk mode
            webView.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;

   
        }

        // --- Logic Loop ---
        private void PlcTimer_Tick(object sender, EventArgs e)
        {
            // 1. Simulate Motion (Move Current towards Target)
            currX = Lerp(currX, targetX, 0.1);
            currY = Lerp(currY, targetY, 0.1);
            currZ = Lerp(currZ, targetZ, 0.1);

            // 2. Prepare Data Packet
            var payload = new
            {
                type = "STATUS_UPDATE",
                sysState = systemState,
                position = new { x = currX, y = currY, z = currZ },
                ioState = GetChangedIOs() // Function to return array of IO states
            };

            string json = JsonConvert.SerializeObject(payload);

            // 3. Send to React via PostMessage (WebView2)
            if (webView != null && webView.CoreWebView2 != null)
            {
                webView.CoreWebView2.PostWebMessageAsJson(json);
            }

            // 4. Broadcast to WebSocket (Dev/HMR)
            _wsServer?.Broadcast(json);
        }

        private List<object> GetChangedIOs()
        {
            // Simply return list of all active IOs or just send all for simplicity
            var list = new List<object>();
            for (int i = 0; i < 32; i++)
            {
                list.Add(new { id = i, type = "input", state = inputs[i] });
                list.Add(new { id = i, type = "output", state = outputs[i] });
            }
            return list;
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            // Setup Simulation Timer (50ms)
            plcTimer = new Timer();
            plcTimer.Interval = 50;
            plcTimer.Tick += PlcTimer_Tick;
            plcTimer.Start();
        }

        // --- Helper Methods called by Bridge ---
        public void SetTargetPosition(string axis, double val)
        {
            if (axis == "X") targetX = val;
            if (axis == "Y") targetY = val;
            if (axis == "Z") targetZ = val;
        }

        public void SetOutput(int id, bool state)
        {
            if (id < 32) outputs[id] = state;
        }

        public void HandleCommand(string cmd)
        {
            systemState = (cmd == "START") ? "RUNNING" : (cmd == "STOP") ? "PAUSED" : "IDLE";
        }

        private double Lerp(double a, double b, double t) => a + (b - a) * t;
    }
}
