import { ReactNode, useEffect, useState } from "react";
import { useLoaderData, useNavigate, useSearchParams } from "react-router-dom";
import { AppLayout, BreadcrumbGroup, Container, Flashbar, FlashbarProps, Header, SpaceBetween, TextContent, Wizard } from "@cloudscape-design/components";
import { AuthComponent, IAuthMode } from "../components/AuthComponent";
import OtpInput from 'react-otp-input';
import { CountdownBar } from "../components/CountdownBar";
import { DoorResponse } from "../types/DoorResponse";
import { fetchUrlEncoded } from "../helpers/FetchHelper";

export async function loader({ params, request }: any) {
  const door = new URL(request.url).searchParams.get('door');

  if (!door) {
    return {};
  }

  const res = await fetchUrlEncoded('/api/door/info', {
    door,
  }).then(res => res.json());

  console.log(res);

  if (res.msg) {
    throw new Error("Not a valid door");
  }

  return res as DoorResponse;
}

export function DoorPage() {
  const doorResponse = useLoaderData() as DoorResponse;
  const navigate = useNavigate();
  const door = doorResponse.id;
  const [ step, setStep ] = useState(0);
  const [searchParams, setSearchParams] = useSearchParams();
  const secret = searchParams.get('key') || searchParams.get('rotatingKey');
  const [ alerts, setAlerts ] = useState<FlashbarProps.MessageDefinition[]>([]);
  const [ polling, setPolling ] = useState(false);
  const [ submitPin, setSubmitPin ] = useState(0);

  const dismissAlert = (id: string) => {
    setAlerts(alerts => alerts.filter(alert => alert.id !== id));
  }

  const dismissInProgressAlerts = () => {
    setAlerts(alerts => alerts.filter(alert => alert.type !== 'in-progress'));
  }

  const createAlert = (type: FlashbarProps.Type, content: ReactNode): FlashbarProps.MessageDefinition => {
    const id = `${Math.random()}`;
    return {
      id,
      type,
      content,
      dismissible: type !== 'in-progress',
      onDismiss: () => dismissAlert(id),
    }
  }

  const addAlert = (type: FlashbarProps.Type, content: ReactNode): string => {
    const newAlert = createAlert(type, content);
    setAlerts(alerts => [
      newAlert,
      ...alerts,
    ]);

    return newAlert.id as string;
  }

  useEffect(() => {
    if (!polling) {
      return;
    }

    const timer = setInterval(async () => {
      const response = await fetchUrlEncoded('/api/door/info', {
        door,
      }).then(res => res.json());

      // polling assumes that the door was opened and whatever closed it was the buzzer system...
      // ie. state transition from OPEN to CLOSED before timeout means that twilio opened the door
      // TODO: this may be a bad assumption in the future but works for now
      if (response.status === "CLOSED") {
        setStep(3);
        setPolling(false);
        setAlerts(alerts => 
          [createAlert("success", "Buzzer successfully unlocked"), ...alerts.filter(alert => alert.type !== 'in-progress')]
        );
      }

    }, 2000);

    return () => {
      clearInterval(timer);
      dismissInProgressAlerts();
    }
  }, [polling]);

  return (
    <AppLayout
      contentType="wizard"
      navigationHide
      toolsHide
      breadcrumbs={
        <BreadcrumbGroup
          items={[
            { text: 'Door', href: '#' },
            { text: door, href: `?edit&door=${door}` },
            { text: 'Unlock', href: '#' },
          ]}
        />
      }
      notifications={
        <Flashbar 
          stackItems={true}
          items={alerts}
        />
      }
      content={
        <Wizard
          i18nStrings={{
            stepNumberLabel: stepNumber =>
              `Step ${stepNumber}`,
            collapsedStepsLabel: (stepNumber, stepsCount) =>
              `Step ${stepNumber} of ${stepsCount}`,
            skipToButtonLabel: (step, stepNumber) =>
              `Skip to ${step.title}`,
            navigationAriaLabel: "Steps",
            cancelButton: "Cancel",
            previousButton: "Previous",
            nextButton: "Next",
            submitButton: "Finish",
            optional: "optional"
          }}
          activeStepIndex={step}
          onNavigate={({ detail }) => {
            if (detail.requestedStepIndex < step) {
              dismissInProgressAlerts();
              setSubmitPin(0);
              setPolling(false);
              setStep(detail.requestedStepIndex);
              return;
            }
            if (detail.requestedStepIndex === 2) {
              setSubmitPin(submitPin + 1);
              return;
            }

            if (detail.requestedStepIndex >= 2) {
              return;
            }

            setStep(detail.requestedStepIndex);
          }}
          onCancel={() => {
            setStep(0);
            dismissInProgressAlerts();
            setSubmitPin(0);
          }}
          steps={[
            {
              title: "Get to the buzzer",
              description:"Before unlocking this door, you should first arrive to the buzzer",
              content: (
                <Container
                  header={
                    <Header variant="h2">
                      Get to the buzzer
                    </Header>
                  }
                >
                  Once you arrive at the buzzer, advance to the next step!
                </Container>
              )
            },
            {
              title: "Authenticate",
              description: "This door is locked by a software system, unlocking it will allow you access",
              content: (
                <Container
                  header={
                    <Header variant="h2">
                      Authenticate
                    </Header>
                  }
                >
                  <AuthComponent 
                    authMode={IAuthMode.FIXED_PIN}
                    runCheck={submitPin}
                    door={door} 
                    secret={secret}
                    onUnlock={() => {
                      setStep(2);
                      dismissInProgressAlerts();
                      addAlert("in-progress", (
                        <CountdownBar 
                          timeSeconds={doorResponse.timeout} 
                          onExpiry={() => {
                            setPolling(false);
                            addAlert("error", "Authentication expired: please try again. If this was a one time link, you need to request a new one");
                            setStep(1);
                          }}
                        />
                      ));

                      setPolling(true);
                    }} 
                  />
                </Container>
              )
            },
            {
              title: "Dial code",
              description: "Type in the buzzer code and the system should automatically allow you access to the building",
              content: (
                <Container
                  header={
                    <Header variant="h2">
                      Dial code
                    </Header>
                  }
                >
                  <SpaceBetween size='l' alignItems="center">
                    <TextContent>
                      <p>Enter the buzzer code at the front entrance</p>
                    </TextContent>
                    <OtpInput
                      containerStyle={{
                        width: "100%",
                        justifyContent: "space-around",
                      }}
                      inputStyle={{
                        margin: '0.5rem',
                        height: '3rem',
                        width: '2rem',
                        fontSize: '2rem',
                      }}
                      value={doorResponse.buzzerCode}
                      numInputs={doorResponse.buzzerCode.length}
                      onChange={() => null}
                      renderSeparator={() => <span>-</span>}
                      renderInput={(props) => <input readOnly {...props} />}
                    />
                    
                  </SpaceBetween>
                </Container>
              )
            },
            {
              title: "Enter the building",
              description: "The buzzer allowed you access, come on up!",
              content: (
                <Container
                  header={
                    <Header variant="h2">
                      Welcome
                    </Header>
                  }
                >
                  <SpaceBetween size='l' alignItems="center">
                    <TextContent>
                      {doorResponse.greeting || "The door is unlocked!"}
                    </TextContent>
                    <img src="/Insulin_Nation_Low_Kramer.gif"/>
                  </SpaceBetween>
                </Container>
              )
            },
          ]}
        />
      }
    />
  );
};
