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

const DEFAULT_DRIVER = {
  driverId: 'driver_001',
  lat: 36.2021,
  lng: 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 DriverPage = () => {
  const [driverId, setDriverId] = useState(DEFAULT_DRIVER.driverId);
  const [lat, setLat] = useState(DEFAULT_DRIVER.lat);
  const [lng, setLng] = useState(DEFAULT_DRIVER.lng);
  const [connected, setConnected] = useState(false);
  const [autoSend, setAutoSend] = useState(false);
  const [socketError, setSocketError] = useState<string | null>(null);
  const [lastPayload, setLastPayload] = useState<DriverLocation | null>(null);
  const [logs, setLogs] = useState<SocketLogItem[]>([]);

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

  const tokenStatus = useMemo(() => (TRACKING_TOKEN ? 'Configured' : 'Missing'), []);

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

  const stopAutoSend = () => {
    if (intervalRef.current) {
      window.clearInterval(intervalRef.current);
      intervalRef.current = null;
    }
    setAutoSend(false);
  };

  const emitLocation = (nextPayload?: DriverLocation) => {
    const payload: DriverLocation =
      nextPayload ?? {
        driverId,
        lat,
        lng,
      };

    if (!socketRef.current || !socketRef.current.connected) {
      appendLog('Cannot send location while disconnected.', 'warning');
      return;
    }

    socketRef.current.emit('driver:updateLocation', payload);
    setLastPayload(payload);
    appendLog(`driver:updateLocation => ${JSON.stringify(payload)}`, 'success');
  };

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

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

    socket.on('connect', () => {
      setConnected(true);
      setSocketError(null);
      appendLog(`Connected (${socket.id})`, 'success');
    });

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

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

    socket.on('connect_error', (err: Error) => {
      const message = err.message || 'Connection error';
      const tokenHint = message.toLowerCase().includes('token')
        ? ' (possible invalid token)'
        : '';
      setSocketError(`${message}${tokenHint}`);
      appendLog(`connect_error: ${message}${tokenHint}`, 'error');
    });

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

  const disconnect = () => {
    stopAutoSend();

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

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

  useEffect(() => {
    if (!autoSend) {
      if (intervalRef.current) {
        window.clearInterval(intervalRef.current);
        intervalRef.current = null;
      }
      return;
    }

    if (!connected) {
      appendLog('Auto send requires an active connection.', 'warning');
      setAutoSend(false);
      return;
    }

    intervalRef.current = window.setInterval(() => {
      const nextLat = Number((lat + (Math.random() - 0.5) * 0.001).toFixed(6));
      const nextLng = Number((lng + (Math.random() - 0.5) * 0.001).toFixed(6));
      setLat(nextLat);
      setLng(nextLng);

      emitLocation({
        driverId,
        lat: nextLat,
        lng: nextLng,
      });
    }, 2000);

    appendLog('Auto send enabled (every 2 seconds).', 'info');

    return () => {
      if (intervalRef.current) {
        window.clearInterval(intervalRef.current);
        intervalRef.current = null;
      }
    };
  }, [autoSend, connected, driverId, lat, lng]);

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

  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">Driver Simulator</h2>
          <StatusBadge connected={connected} />
        </div>

        <div className="grid gap-4 md:grid-cols-2">
          <div className="rounded-xl bg-slate-50 p-4">
            <p className="text-xs uppercase tracking-wide text-slate-500">Socket URL</p>
            <p className="mt-1 break-all text-sm font-medium text-slate-700">{SOCKET_URL}</p>
          </div>
          <div className="rounded-xl bg-slate-50 p-4">
            <p className="text-xs uppercase tracking-wide text-slate-500">Token Status</p>
            <p
              className={`mt-1 text-sm font-semibold ${
                TRACKING_TOKEN ? 'text-emerald-700' : 'text-rose-700'
              }`}
            >
              {tokenStatus}
            </p>
          </div>
        </div>

        <div className="mt-5 grid gap-4 md:grid-cols-3">
          <label className="space-y-1">
            <span className="text-sm font-medium text-slate-700">Driver ID</span>
            <input
              value={driverId}
              onChange={(e) => setDriverId(e.target.value)}
              className="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm outline-none ring-0 focus:border-indigo-400"
            />
          </label>
          <label className="space-y-1">
            <span className="text-sm font-medium text-slate-700">Latitude</span>
            <input
              type="number"
              value={lat}
              onChange={(e) => setLat(Number(e.target.value))}
              className="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm outline-none ring-0 focus:border-indigo-400"
            />
          </label>
          <label className="space-y-1">
            <span className="text-sm font-medium text-slate-700">Longitude</span>
            <input
              type="number"
              value={lng}
              onChange={(e) => setLng(Number(e.target.value))}
              className="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm outline-none ring-0 focus:border-indigo-400"
            />
          </label>
        </div>

        <div className="mt-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>
          <button
            onClick={() => emitLocation()}
            className="rounded-lg bg-emerald-600 px-4 py-2 text-sm font-medium text-white hover:bg-emerald-700"
          >
            Send Location
          </button>
          <button
            onClick={() => setAutoSend((prev) => !prev)}
            className={`rounded-lg px-4 py-2 text-sm font-medium text-white ${
              autoSend ? 'bg-amber-600 hover:bg-amber-700' : 'bg-sky-600 hover:bg-sky-700'
            }`}
          >
            {autoSend ? 'Stop Auto Send' : 'Start Auto Send'}
          </button>
        </div>

        {socketError && (
          <div className="mt-4 rounded-lg border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-700">
            Socket Error: {socketError}
          </div>
        )}

        <div className="mt-4 rounded-lg bg-slate-50 p-3 text-sm text-slate-700">
          <p className="font-semibold">Last Emitted Payload</p>
          <pre className="mt-2 overflow-auto rounded bg-slate-900 p-3 text-xs text-slate-100">
            {lastPayload ? JSON.stringify(lastPayload, null, 2) : 'No payload sent yet.'}
          </pre>
        </div>
      </div>

      <EventLog logs={logs} />
    </div>
  );
};
