import { useEffect, useMemo, useRef, useState } from 'react';
import type { Socket } from 'socket.io-client';
import { DriverMap } from '../components/DriverMap';
import { DriverTable } from '../components/DriverTable';
import { EventLog } from '../components/EventLog';
import { StatusBadge } from '../components/StatusBadge';
import { createTrackingSocket, SOCKET_URL } from '../services/socket';
import type {
  DashboardUpdatePayload,
  DriverLocation,
  DriverRecord,
  SocketLogItem,
  SocketLogLevel,
} from '../types/tracking';

const DEFAULT_CENTER: [number, number] = [36.2021, 37.1343];

const makeLog = (message: string, level: SocketLogLevel = 'info'): SocketLogItem => ({
  id: `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
  message,
  level,
  timestamp: new Date().toLocaleTimeString(),
});

export const DashboardPage = () => {
  const [connected, setConnected] = useState(false);
  const [drivers, setDrivers] = useState<Record<string, DriverRecord>>({});
  const [logs, setLogs] = useState<SocketLogItem[]>([]);
  const [requestDriverId, setRequestDriverId] = useState('driver_001');
  const [latestRequestedLocation, setLatestRequestedLocation] = useState<DriverLocation | DriverLocation[] | null>(null);

  const socketRef = useRef<Socket | null>(null);

  const appendLog = (message: string, level: SocketLogLevel = 'info') => {
    setLogs((prev) => [makeLog(message, level), ...prev].slice(0, 120));
  };

  const upsertDriver = (driver: DriverLocation) => {
    setDrivers((prev) => ({
      ...prev,
      [driver.driverId]: {
        ...driver,
        lastUpdated: new Date().toLocaleTimeString(),
      },
    }));
  };

  const handleDashboardUpdate = (payload: DashboardUpdatePayload) => {
    if (Array.isArray(payload)) {
      payload.forEach((driver) => upsertDriver(driver));
      appendLog(`dashboard:update received snapshot (${payload.length} drivers)`, 'success');
      return;
    }

    upsertDriver(payload);
    appendLog(`dashboard:update => ${payload.driverId} (${payload.lat}, ${payload.lng})`, 'success');
  };

  const connect = () => {
    if (socketRef.current?.connected) {
      appendLog('Already connected.', 'info');
      return;
    }

    const socket = createTrackingSocket();
    socketRef.current = socket;

    socket.on('connect', () => {
      setConnected(true);
      appendLog('Dashboard socket connected.', 'success');
    });

    socket.on('disconnect', (reason) => {
      setConnected(false);
      appendLog(`Disconnected: ${reason}`, 'warning');
    });

    socket.io.on('reconnect', (attempt) => {
      appendLog(`Reconnected after ${attempt} attempt(s).`, 'success');
    });

    socket.on('connect_error', (err: Error) => {
      appendLog(`connect_error: ${err.message || 'Connection failed'}`, 'error');
    });

    socket.on('dashboard:update', (payload: DashboardUpdatePayload) => {
      try {
        handleDashboardUpdate(payload);
      } catch {
        appendLog('Invalid dashboard:update payload received.', 'error');
      }
    });

    socket.on('client:driverLocation', (payload: DriverLocation | DriverLocation[]) => {
      setLatestRequestedLocation(payload);
      appendLog('client:driverLocation response received.', 'success');

      if (Array.isArray(payload)) {
        payload.forEach((driver) => upsertDriver(driver));
      } else {
        upsertDriver(payload);
      }
    });

    socket.connect();
    appendLog('Connecting dashboard socket...', 'info');
  };

  const disconnect = () => {
    if (socketRef.current) {
      socketRef.current.removeAllListeners();
      socketRef.current.disconnect();
      socketRef.current = null;
    }

    setConnected(false);
    appendLog('Dashboard socket disconnected cleanly.', 'warning');
  };

  const requestDriverLocation = () => {
    if (!socketRef.current || !socketRef.current.connected) {
      appendLog('Connect dashboard before requesting location.', 'warning');
      return;
    }

    const payload = { driverId: requestDriverId };
    socketRef.current.emit('client:getDriverLocation', payload);
    appendLog(`client:getDriverLocation => ${JSON.stringify(payload)}`, 'info');
  };

  useEffect(() => {
    return () => {
      if (socketRef.current) {
        socketRef.current.disconnect();
        socketRef.current = null;
      }
    };
  }, []);

  const driverList = useMemo(() => {
    return Object.values(drivers).sort((a, b) => a.driverId.localeCompare(b.driverId));
  }, [drivers]);

  return (
    <div className="space-y-6">
      <div className="rounded-2xl border border-slate-200 bg-white p-5 shadow-sm">
        <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
          <h2 className="text-lg font-semibold text-slate-800">Tracking Dashboard</h2>
          <StatusBadge connected={connected} />
        </div>

        <p className="mb-5 text-sm text-slate-600">
          Socket URL: <span className="font-medium text-slate-800">{SOCKET_URL}</span>
        </p>

        <div className="mb-5 flex flex-wrap gap-3">
          <button
            onClick={connect}
            className="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700"
          >
            Connect
          </button>
          <button
            onClick={disconnect}
            className="rounded-lg bg-slate-700 px-4 py-2 text-sm font-medium text-white hover:bg-slate-800"
          >
            Disconnect
          </button>
        </div>

        <div className="grid gap-3 md:grid-cols-[1fr_auto]">
          <input
            value={requestDriverId}
            onChange={(e) => setRequestDriverId(e.target.value)}
            placeholder="driver_001"
            className="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm outline-none focus:border-indigo-400"
          />
          <button
            onClick={requestDriverLocation}
            className="rounded-lg bg-emerald-600 px-4 py-2 text-sm font-medium text-white hover:bg-emerald-700"
          >
            Request Driver Location
          </button>
        </div>

        <div className="mt-4 rounded-lg bg-slate-50 p-3 text-sm text-slate-700">
          <p className="font-semibold">Latest client:driverLocation response</p>
          <pre className="mt-2 overflow-auto rounded bg-slate-900 p-3 text-xs text-slate-100">
            {latestRequestedLocation
              ? JSON.stringify(latestRequestedLocation, null, 2)
              : 'No response received yet.'}
          </pre>
        </div>
      </div>

      <DriverMap drivers={driverList} defaultCenter={DEFAULT_CENTER} zoom={13} />
      <DriverTable drivers={driverList} />
      <EventLog logs={logs} />
    </div>
  );
};
