import { invoke } from '@tauri-apps/api/core';

import { useState } from 'react';
import './App.css';
import { DSP, DSPStatus, AppPage } from './types/types';
import TopBar from './components/Topbar/Topbar';
import DSPPage from './pages/DspPage/DspPage';
import AddDSPForm from './pages/AddDspPage/AddDspPage';
import { useNotifications } from './hooks/useNotifications';
import Notifications from './components/Notifications/Notifications';
import { DSPState } from './types/dsp408State';
import CreditsPage from './pages/CreditsPage/CreditsPage';
import HomePage from './pages/HomePage/HomePage';

function App() {
  const [dsps, setDsps] = useState<DSP[]>([]);
  const [selected, setSelected] = useState<number | null>(null);
  const [page, setPage] = useState<AppPage>('home');
  const { notifications, notify, removeNotification, hoverNotification } = useNotifications();

  async function addDSP(dsp: Omit<DSP, 'id' | 'status'>) {
    try {
      const id = await invoke<number>('create_dsp408', {
        ip: dsp.ip,
        port: dsp.port,
        deviceId: Number(dsp.deviceId),
      });

      const newDsp: DSP = {
        id,
        ...dsp,
        status: 'disconnected',
      };

      setDsps((prev) => [...prev, newDsp]);
      setSelected(id);
      setPage('view-dsp');

      notify('Added successfully', 'success', dsp.name);
    } catch (err) {
      notify(`Connection failed: ${String(err)}`, 'error', dsp.name);
    }
  }

  async function removeDSP(dsp: DSP) {
    try {
      let id = dsp.id;
      await invoke('remove_dsp408', {
        id,
      });

      setDsps((prev) => {
        const next = prev.filter((d) => d.id !== id);

        if (selected === id) {
          setSelected(next.length ? next[0].id : null);
        }

        return next;
      });

      notify('Removed successfully', 'success', dsp?.name);
    } catch (err) {
      notify(`Remove failed: ${String(err)}`, 'error', dsp?.name);
    }
  }

  async function connectDSP(dsp: DSP) {
    setStatus(dsp.id, 'connecting');

    try {
      await invoke('connect_dsp408', {
        id: dsp.id,
      });

      console.log('Connected');

      setStatus(dsp.id, 'connected');

      const state = await getDSPState(dsp);

      console.log(state);

      notify('Connected', 'success', dsp.name);
    } catch (err) {
      notify(`Connection failed: ${String(err)}`, 'error', dsp.name);

      setStatus(dsp.id, 'disconnected');
    }
  }

  async function disconnectDSP(dsp: DSP) {
    try {
      await invoke('disconnect_dsp408', {
        id: dsp.id,
      });

      setStatus(dsp.id, 'disconnected');

      notify('Disconnected', 'success', dsp.name);
    } catch (err) {
      notify(`Disconnect failed: ${String(err)}`, 'error', dsp.name);
    }
  }

  async function getDSPState(dsp: DSP) {
    try {
      const state = await invoke<DSPState>('get_dsp_state', {
        id: dsp.id,
      });

      return state;
    } catch (err) {
      notify(`Failed to get state: ${String(err)}`, 'error', dsp.name);

      return null;
    }
  }

  function setStatus(id: number, status: DSPStatus) {
    setDsps((prev) => prev.map((d) => (d.id === id ? { ...d, status } : d)));
  }

  const activeDsp = dsps.find((d) => d.id === selected) ?? null;
  const connectedDspCount = dsps.filter((dsp) => dsp.status === 'connected').length;

  return (
    <div className="app">
      <Notifications
        notifications={notifications}
        onRemove={removeNotification}
        onHover={hoverNotification}
      />

      <TopBar
        dsps={dsps}
        selected={selected}
        page={page}
        setPage={setPage}
        setSelect={setSelected}

        onSelect={(id) => {
          setSelected(id);
          setPage('view-dsp');
        }}

        onRemove={removeDSP}

        onAddClick={() => {
          setPage('add-dsp');
        }}
      />

      <main className="stage">
        {page === 'credits' ? (
          <CreditsPage />
        ) : page === 'add-dsp' ? (
          <AddDSPForm onCancel={() => setPage('home')} onAdd={addDSP} />
        ) : activeDsp ? (
          <DSPPage
            dsp={activeDsp}
            onConnect={() => connectDSP(activeDsp)}
            onDisconnect={() => disconnectDSP(activeDsp)}
            notify={notify}
          />
        ) : (
          <HomePage
            onAddDSP={() => setPage('add-dsp')}
            dspCount={dsps.length}
            connectedCount={connectedDspCount}
          />
        )}
      </main>
    </div>
  );
}

export default App;
