import Page, {PageBody, PageFlexColumn, PageFlexRow} from "../primitives/page/Page";
import Header, {HeaderButton, HeaderTitle} from "../primitives/header/Header";
import {TitleLine} from "../primitives/misc/Misc";
import {Size} from "../models/Shared";
import Blob, {BlobInput, BlobText} from "../primitives/blob/Blob";
import {Icon} from "../primitives/Shared";
import {
  faChain,
  faCheck, faChevronDown,
  faChevronLeft,
  faChevronUp, faMessage,
  faPencilAlt,
  faTag,
  faTrashCan
} from "@fortawesome/free-solid-svg-icons";
import {useCallback, useContext, useEffect, useMemo, useState} from "react";
import LoadingPage from "./LoadingPage";
import {useNavigate, useParams} from "react-router";
import DeviceContext from "../contexts/DeviceContext";
import {useSearchParams} from "react-router-dom";
import {Device} from "../models/Devices";
import deviceRepo from "../actions/devices";
import RuntimeContext from "../contexts/RuntimeContext";

interface DevicePageProps {
  edit?: boolean
}

export default function DevicePage({edit}: DevicePageProps): JSX.Element {
  const {devices} = useContext(DeviceContext);
  const navigate = useNavigate();
  const {id} = useParams();
  const [search] = useSearchParams();

  const device = useMemo(() => devices?.find(d => d.id === id) || null, [devices]);

  if (edit && id === undefined) {
    return <NewDevicePage/>;
  } else if (edit && device) {
    return <EditDevicePage device={device}/>;
  } else if (device !== null) {
    return <ViewDevicePage device={device}/>;
  } else {
    if (devices !== null) {
      navigate("/");
    }

    return <LoadingPage text="Henter enhet"/>;
  }
}

function NewDevicePage(): JSX.Element {
  const navigate = useNavigate();
  const {refreshDevices} = useContext(DeviceContext);

  const [name, setName] = useState<string>("");
  const [connectionString, setConnectionString] = useState<string>("");
  const [wait, setWait] = useState<boolean>();

  const onSave = useCallback(async () => {
    setWait(true);
    if (await deviceRepo().save({name, connectionString})) {
      refreshDevices();
      navigate("/");
    } else {
      setWait(false);
    }
  }, [name, connectionString]);

  if (wait) {
    return <LoadingPage text="Legger til enhet"/>;
  }

  return (
    <Page>
      <Header>
        <HeaderButton onClick={() => navigate("/")}>
          <Icon value={faChevronLeft}/>
        </HeaderButton>
        <HeaderTitle>Ny enhet</HeaderTitle>
      </Header>
      <PageBody>
        <PageFlexRow collapseOn={Size.Mobile}>
          <PageFlexColumn flex={1}>
            <TitleLine>Enhet</TitleLine>
            <Blob fillOn={Size.Any}>
              <BlobText>Navn</BlobText>
              <BlobInput flex={1} type="text" value={name} onChange={setName}/>
            </Blob>
            <Blob fillOn={Size.Any}>
              <BlobText>Adresse</BlobText>
              <BlobInput flex={1} type="text" value={connectionString} onChange={setConnectionString}/>
            </Blob>
            <Blob color="green" onClick={onSave}>
              <BlobText>
                <Icon value={faCheck}/> Lagre
              </BlobText>
            </Blob>
          </PageFlexColumn>
          <PageFlexColumn flex={1}/>
        </PageFlexRow>
      </PageBody>
    </Page>
  );
}


interface EditDevicePageProps {
  device: Device
}

function EditDevicePage({device}: EditDevicePageProps): JSX.Element {
  const navigate = useNavigate();
  const {refreshDevices} = useContext(DeviceContext);

  const [name, setName] = useState<string>(device.name);
  const [connectionString, setConnectionString] = useState<string>(device.connectionString);
  const [wait, setWait] = useState<boolean>();

  const onSave = useCallback(async () => {
    setWait(true);
    if (await deviceRepo().save({id: device.id, name, connectionString})) {
      refreshDevices();
      navigate(`/devices/${device.id}`);
    } else {
      setWait(false);
    }
  }, [device, name, connectionString]);

  if (wait) {
    return <LoadingPage text="Oppdaterer enhet"/>;
  }

  return (
    <Page>
      <Header>
        <HeaderButton onClick={() => navigate(`/devices/${device.id}`)}>
          <Icon value={faChevronLeft}/>
        </HeaderButton>
        <HeaderTitle>Endre «{device.name}»</HeaderTitle>
      </Header>
      <PageBody>
        <PageFlexRow collapseOn={Size.Mobile}>
          <PageFlexColumn flex={1}>
            <TitleLine>Enhet</TitleLine>
            <Blob fillOn={Size.Any}>
              <BlobText>Navn</BlobText>
              <BlobInput flex={1} type="text" value={name} onChange={setName}/>
            </Blob>
            <Blob fillOn={Size.Any}>
              <BlobText>Adresse</BlobText>
              <BlobInput flex={1} type="text" value={connectionString} onChange={setConnectionString}/>
            </Blob>
            <Blob color="green" onClick={onSave}>
              <BlobText>
                <Icon value={faCheck}/> Lagre
              </BlobText>
            </Blob>
          </PageFlexColumn>
          <PageFlexColumn flex={1}/>
        </PageFlexRow>
      </PageBody>
    </Page>
  );
}

interface ViewDevicePageProps {
  device: Device
}

function ViewDevicePage({device}: ViewDevicePageProps): JSX.Element {
  const navigate = useNavigate();
  const {refreshDevices} = useContext(DeviceContext);
  const {active, ended, error, create} = useContext(RuntimeContext);

  const onDelete = useCallback(() => {
    if (!window.confirm("Vil du fjerne denne enheten?")) return;

    deviceRepo().delete(device.id).then(() => {
      refreshDevices();
      navigate("/");
    })
  }, [device, navigate, refreshDevices]);

  return (
    <Page>
      <Header>
        <HeaderButton onClick={() => navigate("/")}>
          <Icon value={faChevronLeft}/>
        </HeaderButton>
        <HeaderTitle>{device.name}</HeaderTitle>
      </Header>
      <PageBody>
        <PageFlexRow collapseOn={Size.Mobile}>
          <PageFlexColumn flex={1}>
            <TitleLine>Enhet</TitleLine>
            <Blob>
              <BlobText>
                <Icon value={faTag}/> {device.name}
              </BlobText>
            </Blob>
            <Blob>
              <BlobText>
                <Icon value={faChain}/> {device.connectionString}
              </BlobText>
            </Blob>
            <Blob color="indigo" onClick={() => navigate(`/devices/${device.id}/edit`)}>
              <BlobText>
                <Icon value={faPencilAlt}/>
              </BlobText>
            </Blob>
            <Blob color="red" onClick={onDelete}>
              <BlobText>
                <Icon value={faTrashCan}/>
              </BlobText>
            </Blob>
          </PageFlexColumn>
          <PageFlexColumn flex={1}>
            <TitleLine>Test</TitleLine>
            {active && !ended ? <TestSection/> : (
              <Blob
                color={error ? "red" : (ended ? "green" : "yellow")}
                onClick={() => create({deviceId: device.id, test: true})}
              >
                {ended && error && <BlobText>Prøv igjen</BlobText>}
                {ended && !error && <BlobText>Vellykket</BlobText>}
                {!ended && <BlobText>Kjør</BlobText>}
              </Blob>
            )}
          </PageFlexColumn>
        </PageFlexRow>
      </PageBody>
    </Page>
  );
}

interface Event {
  createdAt: string,
  type: "up" | "down" | "log",
  message: string
}

function currentTime(): string {
  return (new Date().toTimeString().substring(0, 8));
}

function TestSection(): JSX.Element {
  const {lastEvent, connect, disconnect, start, stop} = useContext(RuntimeContext);
  const [events, setEvents] = useState<Event[]>([]);

  useEffect(() => {
    const timeouts: number[] = [];

    if (lastEvent) {
      const createdAt = (new Date().toTimeString().substring(0, 8));

      if (lastEvent.workout) {
        setEvents(prev => [
          ...prev,
          {createdAt, type: "down", message: `Opprettet økt ${lastEvent.workout!.id}`},
          {createdAt, type: "log", message: "Vil koble til umiddelbart"},
        ]);
      }
      if (lastEvent.workoutStates && lastEvent.workoutStates.length > 0) {
        const last = lastEvent.workoutStates[lastEvent.workoutStates.length - 1];

        setEvents(prev => [...prev, {
          createdAt, type: "down", message: `Ny tilstand: ${last.time} s, ${last.calories} kcal`,
        }])
      }
      if (lastEvent.event) {
        setEvents(prev => [
          ...prev,
          {createdAt, type: "down", message: `Ny hendelse: ${lastEvent.event!.name}`},
        ]);

        if (lastEvent.event.name === "Connected") {
          setEvents(prev => [
            ...prev,
            {createdAt, type: "log", message: "Vil starte om 5 sekunder..."},
          ]);

          timeouts.push(setTimeout(() => {
            setEvents(prev => [
              ...prev,
              {createdAt: currentTime(), type: "up", message: "Starter"},
            ]);
            start();
          }, 5000));
        }

        if (lastEvent.event.name === "Started") {
          setEvents(prev => [
            ...prev,
            {createdAt, type: "log", message: "Vil stoppe om 30 sekunder..."},
          ]);

          timeouts.push(setTimeout(() => {
            setEvents(prev => [
              ...prev,
              {createdAt: currentTime(), type: "up", message: "Stopper"},
            ]);
            stop();
          }, 30000));
        }

        if (lastEvent.event.name === "Stopped") {
          setEvents(prev => [
            ...prev,
            {createdAt, type: "log", message: "Vil koble fra om 5 sekunder..."},
          ]);

          timeouts.push(setTimeout(() => {
            setEvents(prev => [
              ...prev,
              {createdAt: currentTime(), type: "up", message: "Kobler fra"},
            ]);
            disconnect();
          }, 5000));
        }


        if (lastEvent.event.name === "Disconnected") {
          setEvents(prev => [
            ...prev,
            {createdAt, type: "log", message: "Frakoblet"},
          ]);
        }
      }

    } else {
      setEvents([]);
    }
  }, [lastEvent]);

  return (
    <>
      {events.map((e, i) => (
        <PageFlexRow key={i}>
          <Blob>
            <BlobText>{e.createdAt}</BlobText>
          </Blob>
          <Blob>
            <BlobText>
              {e.type === "up" && <Icon value={faChevronUp}/>}
              {e.type === "down" && <Icon value={faChevronDown}/>}
              {e.type === "log" && <Icon value={faMessage}/>}
            </BlobText>
          </Blob>
          <Blob flex={1}>
            <BlobText>{e.message}</BlobText>
          </Blob>
        </PageFlexRow>
      ))}
      <div style={{height: "100px"}}/>
    </>
  );
}
