"use client";

import React, { useEffect, useState, useRef, useCallback } from 'react';
import mqtt from 'mqtt';
import { Menu, Zap } from 'lucide-react';
import Sidebar from '@/components/Sidebar';
import Header from '@/components/Header';
import StatCards from '@/components/StatCards';
import dynamic from 'next/dynamic';
const VoltageChart = dynamic(() => import('@/components/VoltageChart'), { ssr: false });
const HistoryPage = dynamic(() => import('@/components/HistoryPage'), { ssr: false });
import EventLog from '@/components/EventLog';
import EventLogsPage from '@/components/EventLogsPage';
import SettingsPanel from '@/components/SettingsPanel';
import Login from '@/components/Login';
import styles from './page.module.css';
import { insertHistoryPoint, insertEvent, fetchHistory, fetchEvents } from '@/lib/db';
import type { HistoryRow, EventRow } from '@/lib/db';

export interface UpsData {
  success: number;
  on: number;
  state: number;
  v: string;
  batt: number;
  battP: number;
  line: number;
  charging: number;
  chgError: number;
  uptime?: number;
  auto?: number;
  battBlink?: number;
  battCritical?: number;
  chargeLv?: number;
  battMax?: number;
  timedShutdown?: number;
  shutdownRemain?: number;
  shutdownSuggestMode?: number;
  shutdownSuggest?: number;
  shutLastTimer?: number;
  chgMode?: number;
  chgOVP?: number;
  chgReducer?: number;
  chgFullTrig?: number;
  chgOFC?: number;
}

export interface UpsEvent {
  id: string;
  message: string;
  time: string;
  severity?: 'info' | 'success' | 'warning' | 'error';
}

// Classify event severity based on message content
function classifySeverity(msg: string): 'info' | 'success' | 'warning' | 'error' {
  const lower = msg.toLowerCase();
  if (lower.includes('error') || lower.includes('fail') || lower.includes('disconnect') || lower.includes('offline')) return 'error';
  if (lower.includes('warn') || lower.includes('critical') || lower.includes('low')) return 'warning';
  if (lower.includes('connect') || lower.includes('online') || lower.includes('subscrib')) return 'success';
  return 'info';
}

// Convert DB history row to chart point
function rowToChartPoint(row: HistoryRow) {
  return {
    time: row.created_at
      ? new Date(row.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })
      : '--:--:--',
    batteryPct: row.battery_pct,
    vBatt: row.v_batt,
  };
}

// Convert DB event row to UpsEvent
function rowToEvent(row: EventRow): UpsEvent {
  return {
    id: String(row.id ?? crypto.randomUUID()),
    message: row.message,
    time: row.created_at
      ? new Date(row.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })
      : '--:--:--',
    severity: row.severity,
  };
}

export default function Dashboard() {
  const [activeTab, setActiveTab] = useState<'dashboard' | 'history' | 'logs' | 'settings'>('dashboard');
  const [isSidebarOpen, setIsSidebarOpen] = useState(false);
  const [upsData, setUpsData] = useState<UpsData | null>(null);
  const [mqttStatus, setMqttStatus] = useState<'Connecting...' | 'Online' | 'Offline'>('Connecting...');
  const [events, setEvents] = useState<UpsEvent[]>([]);
  const [chartData, setChartData] = useState<{ time: string; batteryPct: number; vBatt: number }[]>([]);
  const [liveChartData, setLiveChartData] = useState<{ time: string; batteryPct: number; vBatt: number }[]>([]);
  const [dbLoaded, setDbLoaded] = useState(false);
  const mqttClientRef = useRef<mqtt.MqttClient | null>(null);
  const prevUpsDataRef = useRef<UpsData | null>(null);
  const lastMqttMessageRef = useRef<number>(0);

  // Throttle: only save to Supabase every 30 seconds
  const lastSaveRef = useRef<number>(0);

  const addEvent = useCallback((msg: string, persist = true) => {
    const severity = classifySeverity(msg);
    const ev: UpsEvent = {
      id: crypto.randomUUID(),
      message: msg,
      time: new Date().toLocaleTimeString(),
      severity,
    };
    setEvents(prev => [ev, ...prev].slice(0, 200));

    // Save to Supabase (for non-trivial messages)
    if (persist) {
      insertEvent({ message: msg, severity } as Partial<EventRow> & Pick<EventRow, 'message' | 'severity'>);
    }
  }, []);

  const clearEvents = async () => {
    const { clearAllEvents } = await import('@/lib/db');
    await clearAllEvents();
    setEvents([]);
  };

  // Auto-clear data if no MQTT message received for 10 seconds (device offline)
  useEffect(() => {
    const interval = setInterval(() => {
      if (lastMqttMessageRef.current > 0) {
        const elapsed = (Date.now() - lastMqttMessageRef.current) / 1000;
        if (elapsed >= 10 && prevUpsDataRef.current !== null) {
          setUpsData(null);
          setLiveChartData([]);
          prevUpsDataRef.current = null;
          addEvent('IoT Device went Offline (No telemetry signal for >10s)', true);
        }
      }
    }, 1000);
    return () => clearInterval(interval);
  }, [addEvent]);

  // Initial data load on mount
  useEffect(() => {
    const loadInitialData = async () => {
      try {
        const [histRows, evRows] = await Promise.all([
          fetchHistory(100),
          fetchEvents(200)
        ]);

        if (histRows.length > 0) {
          const points = histRows.map(rowToChartPoint);
          setChartData(points);
        }
        if (evRows.length > 0) {
          const evs = evRows
            .map(rowToEvent)
            .filter(ev => 
              !ev.message.startsWith('Connected to') && 
              !ev.message.startsWith('Subscribed to') && 
              !ev.message.startsWith('Connecting to') && 
              !ev.message.startsWith('Subscription error') &&
              !ev.message.startsWith('MQTT Connection Offline')
            );
          setEvents(evs);
        }
        setDbLoaded(true);
      } catch (err) {
        console.warn('[DB] initial load warning:', err);
      }
    };

    loadInitialData();
  }, []);

  // MQTT Connection setup
  useEffect(() => {
    setMqttStatus('Connecting...');
    console.log('Connecting to MQTT Broker (wss://broker.emqx.io:8084/mqtt)...');

    const client = mqtt.connect('wss://broker.emqx.io:8084/mqtt');
    mqttClientRef.current = client;

    client.on('connect', () => {
      setMqttStatus('Online');
      console.log('Connected to MQTT Broker');
      client.subscribe('ups/dev15/state', (err) => {
        if (err && err.message !== 'client disconnecting') {
          console.warn(`Subscription warning: ${err.message}`);
        }
      });
    });

    client.on('message', (topic, message) => {
      if (topic === 'ups/dev15/state') {
        try {
          // Sanitize the string: remove control characters like \n, \t, etc. that might break JSON parse
          const rawString = message.toString().replace(/[\x00-\x1F\x7F-\x9F]/g, "");
          const data: UpsData = JSON.parse(rawString);
          lastMqttMessageRef.current = Date.now();
          setUpsData(data);

          // Track state changes to generate event logs
          const prevData = prevUpsDataRef.current;
          if (prevData) {
            // Power Source change
            if (prevData.line !== data.line) {
              if (data.line > 0) addEvent('AC Power Restored (Line Active)', true);
              else addEvent('AC Power Lost (Running on Battery)', true);
            }
            // Output State change
            if (prevData.on !== data.on) {
              if (data.on === 1) addEvent('UPS Output turned ON', true);
              else addEvent('UPS Output turned OFF', true);
            }
            // Battery Critical
            if (prevData.battCritical !== data.battCritical && data.battCritical === 1) {
              addEvent('WARNING: Battery level is CRITICAL', true);
            }
            // Charging state
            if (prevData.charging !== data.charging) {
              if (data.charging === 0 && data.battP >= 95) addEvent('Battery Fully Charged', true);
              else if (data.charging === 1) addEvent('Battery is now charging', false);
            }
            // Shutdown Timer
            if ((prevData.shutdownRemain ?? 0) === 0 && (data.shutdownRemain ?? 0) > 0) {
              addEvent(`Shutdown timer started (${data.shutdownRemain}s)`, true);
            } else if ((prevData.shutdownRemain ?? 0) > 0 && (data.shutdownRemain ?? 0) === 0 && data.on === 1) {
              addEvent('Shutdown timer cancelled', true);
            }
          }
          prevUpsDataRef.current = data;

          const newPoint = {
            time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }),
            batteryPct: data.battP,
            vBatt: parseFloat(data.v),
          };

          setChartData(prev => [...prev, newPoint].slice(-100));
          setLiveChartData(prev => [...prev, newPoint].slice(-15));

          // Throttled save to Supabase (every 30 seconds)
          const now = Date.now();
          if (now - lastSaveRef.current >= 30000) {
            lastSaveRef.current = now;
            insertHistoryPoint({
              v_batt: parseFloat(data.v),
              battery_pct: data.battP,
              line_state: data.line,
              power_on: data.on === 1,
            });
          }

        } catch (e) {
          // Changed to console.warn to prevent Next.js from throwing a red error overlay in dev mode
          console.warn('JSON parse error (likely malformed MQTT data):', e);
        }
      }
    });

    client.on('offline', () => {
      setMqttStatus('Offline');
      console.log('MQTT Connection Offline');
    });

    return () => {
      client.end();
    };
  }, [dbLoaded, addEvent]);

  return (
    <div className={styles.layout}>
      <Sidebar activeTab={activeTab} onTabChange={setActiveTab} isOpen={isSidebarOpen} onClose={() => setIsSidebarOpen(false)} />
      <main className={styles.mainContent}>
        <div className={styles.mobileHeader}>
          <div className={styles.mobileTitle}>
            <Zap color="#2563eb" size={24} strokeWidth={2.5} />
            <span>UPS Monitor</span>
          </div>
          <button className={styles.menuBtn} onClick={() => setIsSidebarOpen(true)} aria-label="Open Menu">
            <Menu size={22} />
          </button>
        </div>
        {activeTab === 'dashboard' && <Header mqttStatus={upsData ? 'Online' : (mqttStatus === 'Connecting...' ? 'Connecting...' : 'Offline')} uptimeSeconds={upsData?.uptime} />}

        {activeTab === 'dashboard' && (
          <>
            <StatCards data={upsData} />
            <div className={styles.gridContent}>
              <VoltageChart data={upsData ? liveChartData : []} />
              <EventLog events={upsData ? events.filter(ev => !ev.message.startsWith('Connected to') && !ev.message.startsWith('Subscribed to') && !ev.message.startsWith('Connecting to')) : []} />
            </div>
          </>
        )}

        {activeTab === 'history' && (
          <HistoryPage data={chartData} />
        )}

        {activeTab === 'logs' && <EventLogsPage events={events} onClear={clearEvents} />}
        
        {activeTab === 'settings' && <SettingsPanel data={upsData} onSendCommand={(cmd, val) => {
          if (mqttClientRef.current && mqttClientRef.current.connected) {
            const payload = JSON.stringify({ cmd, val: String(val) });
            mqttClientRef.current.publish('ups/dev15/cmd', payload);
            addEvent(`Sent command: ${cmd}=${val}`, false);
          } else {
            alert("MQTT is not connected. Cannot send command.");
          }
        }} />}
      </main>
    </div>
  );
}
