import { Alert, AppLayout, BreadcrumbGroup, Button, Container, Flashbar, FlashbarProps, Form, FormField, Header, Input, Link, SpaceBetween } from "@cloudscape-design/components";
import { useLoaderData, useSearchParams } from "react-router-dom";
import { DoorResponse } from "../types/DoorResponse";
import { useForm } from "react-hook-form";
import { InputTokenGroup } from "../components/InputTokenGroup";
import { ReactNode, useState } from "react";
import CInput from "react-hook-form-cloudscape/components/input";
import CTextArea from "react-hook-form-cloudscape/components/textarea";
import { fetchUrlEncoded } from "../helpers/FetchHelper";

export type DoorEditForm = DoorResponse & { pin: string, fallbackNumber: string, discordUser: string, isConfirmed: boolean };

const EDIT_ROUTE = '/api/door/edit';
const ONBOARD_ROUTE = '/api/door/onboard';

export interface EditPageProps {
  isOnboarding?: boolean;
}

export const EditPage = ({ isOnboarding }: EditPageProps) => {
  const doorResponse = useLoaderData() as DoorResponse;
  const door = doorResponse.id;
  const [params, setParams] = useSearchParams();

  const buzzer = params.get("buzzer") || undefined;

  const { setValue, setError, getValues, watch, formState, clearErrors, control, register } = useForm<DoorEditForm>({
    defaultValues: {
      ...doorResponse,
      buzzer,
      isConfirmed: !isOnboarding,
    },
    mode: "all",
  });
  

  const [ alerts, setAlerts ] = useState<FlashbarProps.MessageDefinition[]>([]);

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

  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;
  }

  const fallbackNumbers = watch("fallbackNumbers") || [];
  const discordUsers = watch("discordUsers") || [];

  const fallbackNumbersError = formState.errors.fallbackNumbers?.message;
  const discordUsersError = formState.errors.discordUsers?.message;

  const backUrl = isOnboarding? '/?onboard': `?door=${door}`;
  const apiRoute = isOnboarding ? ONBOARD_ROUTE: EDIT_ROUTE;

  return (     
    <AppLayout
      contentType="form"
      navigationHide
      toolsHide
      breadcrumbs={
        <BreadcrumbGroup
          items={[
            { text: 'Door', href: backUrl },
            isOnboarding ? { text: "Onboard Form", href: `?onboardForm&buzzer=${buzzer}` }: { text: door, href: `?edit&door=${door}` },
          ]}
        />
      }
      notifications={
        <Flashbar 
          stackItems={true}
          items={alerts}
        />
      }
      content={
        <Form
          actions={
            <SpaceBetween direction="horizontal" size="xs">
              <Button formAction="none" variant="link" href={backUrl}>
                Cancel
              </Button>
              <Button 
                variant="primary"
                onClick={() => {
                  if (isOnboarding && !getValues("isConfirmed")) {
                    setError("isConfirmed", {
                      type: "manual",
                      message: "Must confirm that Doorman number is configured",
                    });
                    return;
                  }
                  const form = {
                    ...getValues(), 
                    id: undefined,
                    name: getValues("id"),
                    timeout: parseInt("" + getValues("timeout"))
                  };

                  const body = {
                    door,
                    newConfig: JSON.stringify(form),
                  };

                  fetchUrlEncoded(apiRoute, body)
                    .then(res => res.json())
                    .then(res => {
                      if (res.msg) {
                        addAlert("error", res.msg);
                        return;
                      }
                      if (!isOnboarding) {
                        addAlert("success", `Created approval, check Discord notifcation from Doorman to confirm and approve the changes`);
                      } else if (res.redirect) {
                        // redirect for discord login
                        addAlert("in-progress", `Created Door, you will now be redirected to Discord login to complete the onboarding`);

                        // redirect in 2 seconds
                        setTimeout(() => {
                          window.location = res.redirect;
                        }, 2_000);
                      }
                    });
                }}
              >
                Submit
              </Button>
            </SpaceBetween>
          }
          header={
            <Header variant="h1">
              {isOnboarding? "Onboard Door": "Edit Door"}
            </Header>
          }
        >
          <Container>
            <SpaceBetween direction="vertical" size="l">
              {isOnboarding &&
                <FormField label="Register Doorman in Building" constraintText="Confirm that you added our number to your buzzer system: 604-757-1824" errorText={formState.errors.isConfirmed?.message}>
                  <label>
                    I have added Doorman's number to my buzzer
                    <input type="checkbox" {...register("isConfirmed")} />
                  </label>
                </FormField>
              }
              <FormField label="Door Name" constraintText="Unique name for this Door, will be used in your Doorman URL">
                <CInput readOnly={!isOnboarding} disabled={!isOnboarding} name="id" control={control} />
              </FormField>
              <FormField label="Buzzer Number" constraintText="Phone number that calls you when your buzzer is called">
                <CInput readOnly={!!buzzer} disabled={!!buzzer} name="buzzer" control={control} />
              </FormField>
              <FormField label="PIN" constraintText={"Code to unlock this Door in Doorman"}>
                <CInput type="password" name="pin" control={control} />
              </FormField>
              <FormField label="Buzzer Code" constraintText={"Extension that is used to reach your unit on your buzzer"}>
                <CInput name="buzzerCode" control={control} />
              </FormField>
              <FormField label="Timeout" constraintText="Time in seconds for the door to remain unlocked from Doorman">
                <CInput type="number" name="timeout" control={control} />
              </FormField>
              <FormField label="Unlock Key" constraintText="Phone digit pressed to grant access">
                <CInput name="pressKey" control={control} />
              </FormField>
              <FormField 
                errorText={fallbackNumbersError}
                label="Fallback numbers" 
                constraintText="Phone numbers to dial through in case Door is not unlocked by Doorman"
              >
                <InputTokenGroup
                  name={"fallbackNumber"}
                  control={control}
                  tokenGroupProps={{ items: fallbackNumbers.map(n => ({ label: n }))}}
                  onAdd={() => {
                    const newValue = getValues().fallbackNumber;
                    if (newValue.length === 0) {
                      return;
                    }
                    clearErrors("fallbackNumbers");
                    setValue("fallbackNumbers", [...fallbackNumbers, newValue]);
                    setValue("fallbackNumber", "");
                  }}
                  onDismiss={(i) => {
                    clearErrors("fallbackNumbers");

                    if (fallbackNumbers.length === 1) {
                      setError("fallbackNumbers", { message: "Can't remove last entry", type: "value" })
                      return;
                    }
                    fallbackNumbers.splice(i, 1);
                    setValue("fallbackNumbers", [...fallbackNumbers]);
                  }}
                />
              </FormField>
              {!isOnboarding &&
                <FormField 
                  label="Discord Users" 
                  errorText={discordUsersError}
                  constraintText={
                    <>
                      <Link fontSize={"body-s"} href="https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID#h_01HRSTXPS5H5D7JBY2QKKPVKNA">Discord users</Link> to receive notifications
                    </>
                  }
                >
                    <InputTokenGroup
                      name={"discordUser"}
                      control={control}
                      tokenGroupProps={{ items: discordUsers.map(n => ({ label: n }))}}
                      onAdd={() => {
                        const newValue = getValues().discordUser;
                        if (newValue.length === 0) {
                          return;
                        }
                        clearErrors("discordUsers");
                        setValue("discordUsers", [...discordUsers, newValue]);
                        setValue("discordUser", "");
                      }}
                      onDismiss={(i) => {
                        clearErrors("discordUsers");

                        if (discordUsers.length === 1) {
                          setError("discordUsers", { message: "Can't remove last entry" })
                          return;
                        }
                        discordUsers.splice(i, 1);
                        setValue("discordUsers", [...discordUsers]);
                      }}
                    />
                </FormField>
              }
              <FormField label="Welcome Message" constraintText="Message to display after a successful unlock">
                <CTextArea name="greeting" control={control} />
              </FormField>
            </SpaceBetween>
          </Container>
        </Form>
      }
    />
  );
};
