import { BasicRadioGroup } from "@/components/form-fields/basic-radio";
import type { DeployLabFormData } from "@/components/labs/deploy-lab-form";
import {
  type LabMetaV2,
  type TiDBEnvironment,
  tidbEnvironmentLocaleKey,
} from "@/components/labs/hooks-v2";
import { LabMetaField, LabMetaName } from "@/components/labs/lab-meta-field";
import { useMe } from "@/components/me-context";
import { NextLink } from "@/components/next-link";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { useLocale, useLocaleFunction } from "@/hooks/use-localed";
import { client } from "@/lib/api-client";
import { type LabMetaExtra } from "@/lib/api/labs";
import { createLabInstance, redeemLabV2 } from "@/lib/api/labs.v2";
import {
  type CloudProvider,
  type ClusterRegionKey,
  toClusterRegionInfo,
} from "@/lib/cluster-regions";
import { getErrorMessage } from "@/lib/errors";
import { transformPathLocale } from "@/lib/locale";
import { sendGTMEvent } from "@next/third-parties/google";
import {
  AlertCircleIcon,
  Loader2Icon,
  SquareArrowOutUpRightIcon,
} from "lucide-react";
import type { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
import { useRouter } from "next/navigation";
import {
  type ComponentProps,
  type MouseEvent,
  type TransitionStartFunction,
  useState,
  useTransition,
} from "react";

export interface DeployLabFormV2Props {
  lab: LabMetaV2 & LabMetaExtra;
  onChange?: (data: DeployLabFormData) => void;
  region?: ClusterRegionKey;
  tidbEnvironment: TiDBEnvironment;
  onTiDBEnvironmentChange?: (environment: TiDBEnvironment) => void;
  serverlessGrantId?: number;
}

interface RedeemProps {
  lab: LabMetaV2 & LabMetaExtra;
}

export function LabMetaInfoFields({
  lab,
  tidbEnvironment,
  onTiDBEnvironmentChange,
}: {
  lab: LabMetaV2;
  tidbEnvironment: TiDBEnvironment;
  onTiDBEnvironmentChange?: (environment: TiDBEnvironment) => void;
}) {
  const t = useLocaleFunction();

  return (
    <>
      <LabMetaName>{t(lab, "title")}</LabMetaName>
      <LabMetaField label="lab.meta.duration">
        {t("lab.meta.duration.minutes", lab?.estimated_duration_minutes)}
      </LabMetaField>
      <LabMetaField
        label="lab.meta.tidb-environment"
        labelFor="tidb-environment-select"
      >
        <Select value={tidbEnvironment} onValueChange={onTiDBEnvironmentChange}>
          <SelectTrigger
            id="tidb-environment-select"
            className="text-foreground"
          >
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {lab.tidb_environments.map((environment) => (
              <SelectItem key={environment} value={environment}>
                {t(tidbEnvironmentLocaleKey(environment) as never)}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </LabMetaField>
    </>
  );
}

export function LabRedeemButton({ lab }: RedeemProps) {
  const router = useRouter();
  const [open, setOpen] = useState(false);
  const [redeeming, startRedeeming] = useTransition();
  const [error, setError] = useState<unknown>(undefined);
  const [transitioning, startTransition] = useTransition();
  const { data: me } = useMe();
  const locale = useLocale();
  const t = useLocaleFunction();

  const handleConfirm = (event: MouseEvent<HTMLButtonElement>) => {
    event.preventDefault();
    startRedeeming(async () => {
      try {
        setError(undefined);
        await redeemLabV2(lab.lab_code);

        setOpen(false);
        startTransition(() => {
          router.refresh();
          client.refetchQueries({
            queryKey: ["lab.meta.next", lab.lab_code],
          });
          client.refetchQueries({
            queryKey: ["user.me"],
          });
        });
      } catch (e) {
        setError(e);
      }
    });
  };

  return (
    <AlertDialog open={open} onOpenChange={setOpen}>
      <AlertDialogTrigger asChild>
        <Button
          className="w-full"
          variant="outline"
          disabled={!lab.credit_redeemable || redeeming || transitioning}
        >
          {t("lab.redeem")}
        </Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>
            {t("lab.redeem.title", t(lab, "title"))}
          </AlertDialogTitle>
          <AlertDialogDescription>
            {t("lab.redeem.description", lab.credits, me?.credits)}
          </AlertDialogDescription>
        </AlertDialogHeader>
        {!!error && (
          <Alert variant="destructive">
            <AlertTitle>{t("lab.alerts.failed-to-redeem")}</AlertTitle>
            <AlertDescription>{getErrorMessage(error)}</AlertDescription>
          </Alert>
        )}
        <AlertDialogFooter>
          <NextLink
            variant="ghost"
            href={transformPathLocale("/get-credits", locale)}
          >
            {t("lab.redeem.buy-credits")}
          </NextLink>
          <AlertDialogAction
            onClick={handleConfirm}
            disabled={
              redeeming || transitioning || !me || me.credits < lab.credits
            }
          >
            {(redeeming || transitioning) && (
              <Loader2Icon className="animate-spin repeat-infinite" />
            )}
            {t("lab.redeem.confirm")}
          </AlertDialogAction>
          <AlertDialogCancel disabled={redeeming || transitioning}>
            {t("lab.redeem.cancel")}
          </AlertDialogCancel>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  );
}

export function LabLearnMoreButton({ lab }: { lab: LabMetaExtra }) {
  const t = useLocaleFunction();
  return (
    <Button className="w-full" asChild>
      <a href={t(lab, "training_class_url")} target="_blank">
        {t("lab.alerts.learn-more")}
        <SquareArrowOutUpRightIcon className="size-4 shrink-0 ml-2" />
      </a>
    </Button>
  );
}

export function LabNotAvailableAlert({ lab }: { lab: LabMetaExtra }) {
  const t = useLocaleFunction();
  return (
    <Alert>
      <AlertCircleIcon />
      <AlertTitle>{t("lab.alerts.not-available")}</AlertTitle>
      <AlertDescription>{lab.suggestion}</AlertDescription>
    </Alert>
  );
}

export type ServerlessClusterTypeRadioItem = {
  value: "user-host" | "sandbox";
  label: string;
  description: string;
};

export function ServerlessClusterTypeRadioGroup({
  disableSandbox = false,
  ...props
}: Omit<
  ComponentProps<typeof BasicRadioGroup<ServerlessClusterTypeRadioItem>>,
  "options"
> & { disableSandbox?: boolean }) {
  const t = useLocaleFunction();

  return (
    <BasicRadioGroup<ServerlessClusterTypeRadioItem>
      {...props}
      disabled={props.disabled || disableSandbox}
      options={
        [
          {
            value: "user-host",
            label: t("lab.meta.cluster-environment.label:user-host"),
            description: t(
              "lab.meta.cluster-environment.description:user-host"
            ),
          },
          !disableSandbox && {
            value: "sandbox",
            label: t("lab.meta.cluster-environment.label:sandbox"),
            description: t("lab.meta.cluster-environment.description:sandbox"),
          },
        ].filter(Boolean) as ServerlessClusterTypeRadioItem[]
      }
    />
  );
}

export function selectDefaultRegion(
  lab: LabMetaV2 & LabMetaExtra,
  value: ClusterRegionKey
): ClusterRegionKey {
  const info = toClusterRegionInfo(value);

  const regions = lab.regions;

  const provider = regions[info.cloud_provider];
  if (provider) {
    if (provider.includes(info.region_name)) {
      return value;
    } else {
      return `${info.cloud_provider}:${provider[0]}`;
    }
  } else {
    const cp = Object.keys(regions)[0] as CloudProvider;
    return `${cp}:${regions[cp]![0]}`;
  }
}

export async function processDeployLab(
  lab: LabMetaV2,
  {
    region,
    ...value
  }: {
    tidb_environment: TiDBEnvironment;
    region: ClusterRegionKey;
    tidb_version?: string;
    user_serverless_cluster_id?: string;
  },
  startTransition: TransitionStartFunction,
  router: AppRouterInstance
) {
  sendGTMEvent(
    {
      event: "lab.start-button.click",
      lab_code: lab.lab_code,
    },
    "gtag"
  );

  const { cloud_provider, region_name } = toClusterRegionInfo(region);

  const { lab_instance_id } = await createLabInstance({
    ...value,
    cloud_provider,
    region_name,
    lab_code: lab.lab_code,
  });

  void client.invalidateQueries({
    queryKey: ["lab.active-instance"],
    refetchType: "all",
  });

  startTransition(() => {
    router.push(`/lab?instance=${lab_instance_id}`);
  });
  sendGTMEvent(
    {
      event: "lab.start-button.click",
      lab_code: lab.lab_code,
    },
    "gtag"
  );
}
