"use client";

import { useState } from "react";
import { useForm, Controller, useFormContext } from "react-hook-form";

import { Dialog } from "@calcom/features/components/controlled-dialog";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { ServiceAccountKey } from "@calcom/lib/server/serviceAccountKey";
import { serviceAccountKeySchema } from "@calcom/prisma/zod-utils";
import { trpc } from "@calcom/trpc/react";
import { Badge } from "@calcom/ui/components/badge";
import { InfoBadge } from "@calcom/ui/components/badge";
import { Button } from "@calcom/ui/components/button";
import { DialogContent, DialogFooter, ConfirmationDialogContent } from "@calcom/ui/components/dialog";
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
import { Form } from "@calcom/ui/components/form";
import { TextAreaField } from "@calcom/ui/components/form";
import { TextField } from "@calcom/ui/components/form";
import { SelectField } from "@calcom/ui/components/form";
import { Switch } from "@calcom/ui/components/form";
import { SkeletonContainer, SkeletonText } from "@calcom/ui/components/skeleton";
import { DropdownActions } from "@calcom/ui/components/table";
import { showToast } from "@calcom/ui/components/toast";

interface DelegationItemProps {
  delegation: {
    id: string;
    domain: string;
    enabled: boolean;
    serviceAccountClientId: string | null;
    workspacePlatform: {
      name: string;
      slug: string;
    };
  };
  toggleDelegation: (delegation: DelegationItemProps["delegation"]) => void;
  onEdit: (delegation: DelegationItemProps["delegation"]) => void;
  onDelete: (id: string) => void;
}

type WorkspacePlatform = {
  id: number;
  name: string;
  slug: string;
};

function getWorkspacePlatformOptions(workspacePlatforms: WorkspacePlatform[]) {
  return workspacePlatforms.map((platform) => ({
    value: platform.slug,
    label: platform.name,
  }));
}

const SkeletonLoader = () => {
  return (
    <SkeletonContainer>
      <div className="divide-subtle border-subtle space-y-6 rounded-b-lg border border-t-0 px-6 py-4">
        <SkeletonText className="h-8 w-full" />
        <SkeletonText className="h-8 w-full" />
      </div>
    </SkeletonContainer>
  );
};

function DelegationListItemActions({
  delegation,
  toggleDelegation,
  onEdit,
  onDelete,
}: {
  delegation: DelegationItemProps["delegation"];
  toggleDelegation: DelegationItemProps["toggleDelegation"];
  onEdit: (delegation: DelegationItemProps["delegation"]) => void;
  onDelete: (id: string) => void;
}) {
  const { t } = useLocale();

  return (
    <div className="flex items-center space-x-2">
      <Switch checked={delegation.enabled} onCheckedChange={() => toggleDelegation(delegation)} />
      <DropdownActions
        actions={[
          {
            id: "edit",
            label: t("edit"),
            onClick: () => onEdit(delegation),
            icon: "pencil",
          },
          {
            id: "delete",
            label: t("delete"),
            disabled: true,
            onClick: () => onDelete(delegation.id),
            icon: "trash",
          },
        ]}
      />
    </div>
  );
}

function DelegationListItem({ delegation, toggleDelegation, onEdit, onDelete }: DelegationItemProps) {
  const { t } = useLocale();
  return (
    <li className="border-subtle bg-default divide-subtle flex flex-col divide-y border">
      <div className="flex items-center justify-between space-x-2 p-4">
        <div className="flex flex-col items-start">
          <div className="flex items-center space-x-2">
            <span>{delegation.serviceAccountClientId}</span>
            <InfoBadge content={t("add_client_id_in_google_workspace_with_below_scope")} />
          </div>
          <span className="text-muted mt-2">https://www.googleapis.com/auth/calendar</span>
          <div className="mt-2 flex items-center space-x-2">
            <Badge variant="default">{delegation.workspacePlatform.name}</Badge>
            <Badge variant="gray">{delegation.domain}</Badge>
          </div>
        </div>
        <DelegationListItemActions
          delegation={delegation}
          toggleDelegation={toggleDelegation}
          onEdit={onEdit}
          onDelete={onDelete}
        />
      </div>
    </li>
  );
}

type CreateDelegationData = {
  domain: string;
  workspacePlatformSlug: string;
  enabled: boolean;
  serviceAccountKey: ServiceAccountKey;
};

type CreateDelegationFormData = Omit<CreateDelegationData, "serviceAccountKey"> & {
  serviceAccountKey: string;
};

type EditDelegationData = {
  id: string;
  domain: string;
  workspacePlatformSlug: string;
  enabled: boolean;
};

function CreateDelegationDialog({
  isOpen,
  onClose,
  workspacePlatforms,
  handleCreate,
}: {
  isOpen: boolean;
  onClose: () => void;
  workspacePlatforms: WorkspacePlatform[];
  handleCreate: (data: CreateDelegationData) => void;
}) {
  const { t } = useLocale();

  const form = useForm<CreateDelegationFormData>();

  const handleSubmit = (values: CreateDelegationFormData) => {
    try {
      const parsedKey = JSON.parse(values.serviceAccountKey);
      const validatedKey = serviceAccountKeySchema.safeParse(parsedKey);

      if (!validatedKey.success) {
        form.setError("serviceAccountKey", { message: t("invalid_service_account_key") });
        return;
      }

      handleCreate({
        ...values,
        serviceAccountKey: validatedKey.data,
      });
    } catch (e) {
      console.log("error", e);
      form.setError("serviceAccountKey", { message: t("invalid_service_account_key") });
      return;
    }
  };

  return (
    <Dialog open={isOpen} onOpenChange={onClose}>
      <DialogContent enableOverflow title={t("add_delegation_credential")}>
        <Form form={form} handleSubmit={handleSubmit}>
          <DelegationFormFields workspacePlatforms={workspacePlatforms} isCreate={true} />
          <DialogFooter>
            <Button type="button" color="secondary" onClick={onClose}>
              {t("cancel")}
            </Button>
            <Button type="submit">{t("create")}</Button>
          </DialogFooter>
        </Form>
      </DialogContent>
    </Dialog>
  );
}

function EditDelegationDialog({
  isOpen,
  onClose,
  delegation,
  workspacePlatforms,
  handleEdit,
}: {
  isOpen: boolean;
  onClose: () => void;
  delegation: DelegationItemProps["delegation"];
  workspacePlatforms: WorkspacePlatform[];
  handleEdit: (data: EditDelegationData) => void;
}) {
  const { t } = useLocale();

  const form = useForm<EditDelegationData>({
    defaultValues: {
      id: delegation.id,
      domain: delegation.domain,
      workspacePlatformSlug: delegation.workspacePlatform.slug,
    },
  });

  return (
    <Dialog open={isOpen} onOpenChange={onClose}>
      <DialogContent title={t("edit_delegation_credential")}>
        <Form form={form} handleSubmit={handleEdit}>
          <DelegationFormFields workspacePlatforms={workspacePlatforms} isCreate={false} />
          <DialogFooter>
            <Button type="button" color="secondary" onClick={onClose}>
              {t("cancel")}
            </Button>
            <Button type="submit">{t("update")}</Button>
          </DialogFooter>
        </Form>
      </DialogContent>
    </Dialog>
  );
}

function DelegationFormFields({
  workspacePlatforms,
  isCreate,
}: {
  workspacePlatforms: WorkspacePlatform[];
  isCreate: boolean;
}) {
  const { t } = useLocale();
  const form = useFormContext();
  return (
    <div className="space-y-4">
      <TextField label={t("domain")} {...form.register("domain")} />
      <Controller
        name="workspacePlatformSlug"
        control={form.control}
        render={({ field: { value, onChange } }) => {
          const platformOptions = getWorkspacePlatformOptions(workspacePlatforms);
          const selectedPlatform = platformOptions.find((opt) => opt.value === value);
          return (
            <SelectField
              required
              label={t("workspace_platform")}
              onChange={(option) => onChange(option?.value)}
              value={selectedPlatform}
              options={platformOptions}
            />
          );
        }}
      />
      {isCreate && (
        <TextAreaField
          required
          label={t("service_account_key")}
          placeholder="{...}"
          {...form.register("serviceAccountKey")}
        />
      )}
    </div>
  );
}

function DelegationCredentialList() {
  const { t } = useLocale();
  const utils = trpc.useContext();
  const { data: delegations, isLoading, error } = trpc.viewer.delegationCredential.list.useQuery();

  const updateMutation = trpc.viewer.delegationCredential.update.useMutation({
    onSuccess: () => utils.viewer.delegationCredential.list.invalidate(),
    onError: (error) => {
      showToast(error.message, "error");
    },
  });

  const toggleEnabledMutation = trpc.viewer.delegationCredential.toggleEnabled.useMutation({
    onSuccess: (data) => {
      if (data) {
        showToast(
          data.enabled ? t("delegation_credential_enabled") : t("delegation_credential_disabled"),
          "success"
        );
        utils.viewer.delegationCredential.list.invalidate();
      }
    },
    onError: (error) => {
      showToast(error.message, "error");
    },
  });

  const createMutation = trpc.viewer.delegationCredential.add.useMutation({
    onSuccess: () => utils.viewer.delegationCredential.list.invalidate(),
    onError: (error) => {
      showToast(error.message, "error");
    },
  });

  const deleteMutation = trpc.viewer.delegationCredential.delete.useMutation({
    onSuccess: () => utils.viewer.delegationCredential.list.invalidate(),
    onError: (error) => {
      showToast(error.message, "error");
    },
  });

  const onDelete = (id: string) => {
    deleteMutation.mutate({ id });
  };

  const [delegationToToggle, setDelegationToToggle] = useState<DelegationItemProps["delegation"] | null>(
    null
  );

  const toggleDelegation = (delegation: DelegationItemProps["delegation"]) => {
    setDelegationToToggle(delegation);
  };

  const handleToggleConfirm = () => {
    if (delegationToToggle) {
      toggleEnabledMutation.mutate({
        id: delegationToToggle.id,
        enabled: !delegationToToggle.enabled,
      });
      setDelegationToToggle(null);
    }
  };

  const [createEditDialog, setCreateEditDialog] = useState<{
    isOpen: boolean;
    delegation: DelegationItemProps["delegation"] | null;
  }>({
    isOpen: false,
    delegation: null,
  });

  const { data: workspacePlatforms, isLoading: isLoadingWorkspacePlatforms } =
    trpc.viewer.delegationCredential.listWorkspacePlatforms.useQuery();

  const enabledWorkspacePlatforms = workspacePlatforms?.filter((platform) => platform.enabled) || [];

  const onEditClick = (delegation: DelegationItemProps["delegation"]) => {
    setCreateEditDialog({ isOpen: true, delegation });
  };

  const onCreateClick = () => setCreateEditDialog({ isOpen: true, delegation: null });

  const handleCreate = (data: CreateDelegationData) => {
    createMutation.mutate({
      domain: data.domain,
      workspacePlatformSlug: data.workspacePlatformSlug,
      serviceAccountKey: data.serviceAccountKey,
    });
    setCreateEditDialog({ isOpen: false, delegation: null });
  };

  const handleEdit = (data: EditDelegationData) => {
    if (!createEditDialog.delegation) {
      return;
    }
    updateMutation.mutate({
      id: createEditDialog.delegation.id,
      domain: data.domain,
      workspacePlatformSlug: data.workspacePlatformSlug,
    });
    setCreateEditDialog({ isOpen: false, delegation: null });
  };

  const AddDwDButton = () => {
    return (
      <Button type="button" color="secondary" StartIcon="plus" className="mt-6" onClick={onCreateClick}>
        {t("add_delegation_credential")}
      </Button>
    );
  };

  if (isLoading || isLoadingWorkspacePlatforms) {
    return <SkeletonLoader />;
  }

  if (error) {
    return <div>{t(error.message)}</div>;
  }

  if (!delegations || !workspacePlatforms) {
    return <div>{t("something_went_wrong")}</div>;
  }

  return (
    <div>
      {!!delegations?.length ? (
        <>
          <ul className="space-y-2 [&>*:last-child]:rounded-b-xl">
            {delegations.map(
              (delegation) =>
                delegation && (
                  <DelegationListItem
                    key={delegation.id}
                    delegation={delegation}
                    toggleDelegation={toggleDelegation}
                    onEdit={onEditClick}
                    onDelete={onDelete}
                  />
                )
            )}
          </ul>
          {/* Disable till we thoroughly test multiple delegation credentials support */}
          {/* <AddDwDButton /> */}
        </>
      ) : (
        <EmptyScreen
          Icon="link"
          headline={t("add_delegation_credential")}
          description={t("delegation_credential_description")}
          className="rounded-b-lg rounded-t-none border-t-0"
          buttonRaw={<AddDwDButton />}
        />
      )}

      {createEditDialog.delegation ? (
        <EditDelegationDialog
          isOpen={createEditDialog.isOpen}
          onClose={() => setCreateEditDialog({ isOpen: false, delegation: null })}
          delegation={createEditDialog.delegation}
          workspacePlatforms={enabledWorkspacePlatforms}
          handleEdit={handleEdit}
        />
      ) : (
        <CreateDelegationDialog
          isOpen={createEditDialog.isOpen}
          onClose={() => setCreateEditDialog({ isOpen: false, delegation: null })}
          workspacePlatforms={enabledWorkspacePlatforms}
          handleCreate={handleCreate}
        />
      )}

      <ToggleDelegationDialog
        delegation={delegationToToggle}
        onClose={() => setDelegationToToggle(null)}
        onConfirm={handleToggleConfirm}
      />
    </div>
  );
}

function MembersThatWillBeAffectedOnDisablingDelegationCredential({
  delegationCredentialId,
}: {
  delegationCredentialId: string;
}) {
  const { t } = useLocale();
  const { data: affectedMembers, isLoading: isLoadingAffectedMembers } =
    trpc.viewer.delegationCredential.getAffectedMembersForDisable.useQuery({ id: delegationCredentialId });

  return (
    <div className="mt-4">
      <strong>{t("members_affected_by_disabling_delegation_credential")}</strong>
      {isLoadingAffectedMembers ? (
        <div>{t("loading")}</div>
      ) : affectedMembers?.length ? (
        <>
          <ul className="list-disc space-y-1 p-1 pl-5 sm:w-80">
            {affectedMembers.slice(0, 5).map((m) => (
              <li className="text-muted text-sm" key={m.email}>
                {m.name ? `${m.name} (${m.email})` : m.email}
              </li>
            ))}
          </ul>
          {affectedMembers.length > 5 && (
            <p className="mt-2 text-sm text-gray-500">
              {t("and_count_more", { count: affectedMembers.length - 5 })}
            </p>
          )}
        </>
      ) : (
        <div className="mt-2">{t("no_members_affected_by_disabling_delegation_credential")}</div>
      )}
    </div>
  );
}
const ToggleDelegationDialog = ({
  delegation,
  onConfirm,
  onClose,
}: {
  delegation: DelegationItemProps["delegation"] | null;
  onConfirm: () => void;
  onClose: () => void;
}) => {
  const { t } = useLocale();

  if (!delegation) {
    return null;
  }

  const isDisablingDelegation = delegation.enabled;

  return (
    <Dialog
      name="toggle-delegation"
      open={!!delegation}
      onOpenChange={(open) => (!open ? onClose() : undefined)}>
      <ConfirmationDialogContent
        title={t(isDisablingDelegation ? "disable_delegation_credential" : "enable_delegation_credential")}
        confirmBtnText={t(isDisablingDelegation ? "disable" : "enable")}
        cancelBtnText={t("cancel")}
        variety={isDisablingDelegation ? "danger" : "success"}
        onConfirm={onConfirm}>
        <p className="mt-5">
          {t(
            isDisablingDelegation
              ? "disable_delegation_credential_description"
              : "enable_delegation_credential_description"
          )}
        </p>
        {isDisablingDelegation && (
          <MembersThatWillBeAffectedOnDisablingDelegationCredential delegationCredentialId={delegation.id} />
        )}
      </ConfirmationDialogContent>
    </Dialog>
  );
};

export default function DelegationCredentialListPage() {
  return <DelegationCredentialList />;
}
