import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@vibe/ui/components/KeyboardDialog';
import { Label } from '@radix-ui/react-label';
import { Textarea } from '@vibe/ui/components/Textarea';
import { Button } from '@vibe/ui/components/Button';
import { Input } from '@vibe/ui/components/Input';
import { Checkbox } from '@vibe/ui/components/Checkbox';
import { Alert, AlertDescription, AlertTitle } from '@vibe/ui/components/Alert';
import BranchSelector from '@/shared/components/tasks/BranchSelector';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { workspacesApi } from '@/shared/lib/api';
import { useTranslation } from 'react-i18next';

import { Workspace } from 'shared/types';
import { Loader2 } from 'lucide-react';
import { create, useModal } from '@ebay/nice-modal-react';
import { useAuth } from '@/shared/hooks/auth/useAuth';
import { useRepoBranches } from '@/shared/hooks/useRepoBranches';
import {
  GhCliHelpInstructions,
  GhCliSetupDialog,
  mapGhCliErrorToUi,
} from '@/shared/dialogs/auth/GhCliSetupDialog';
import type {
  GhCliSupportContent,
  GhCliSupportVariant,
} from '@/shared/dialogs/auth/GhCliSetupDialog';
import type { GhCliSetupError } from 'shared/types';
import { useUserSystem } from '@/shared/hooks/useUserSystem';
import { defineModal } from '@/shared/lib/modals';
import { splitMessageToTitleDescription } from '@/shared/lib/string';

interface CreatePRDialogProps {
  attempt: Workspace;
  repoId: string;
  targetBranch?: string;
  issueIdentifier?: string;
}

export type CreatePRDialogResult = {
  success: boolean;
  error?: string;
};

const PR_TITLE_SUFFIX = ' (vibe-kanban)';

const appendPrTitleSuffix = (title: string): string => {
  const trimmedTitle = title.trim();
  if (!trimmedTitle) return trimmedTitle;
  if (trimmedTitle.endsWith(PR_TITLE_SUFFIX)) return trimmedTitle;
  return `${trimmedTitle}${PR_TITLE_SUFFIX}`;
};

const CreatePRDialogImpl = create<CreatePRDialogProps>(
  ({ attempt, repoId, targetBranch, issueIdentifier }) => {
    const modal = useModal();
    const { t } = useTranslation('tasks');
    const { isLoaded } = useAuth();
    const { environment, config } = useUserSystem();
    const [prTitle, setPrTitle] = useState('');
    const [prBody, setPrBody] = useState('');
    const [prBaseBranch, setPrBaseBranch] = useState('');
    const [creatingPR, setCreatingPR] = useState(false);
    const [error, setError] = useState<string | null>(null);
    const [ghCliHelp, setGhCliHelp] = useState<GhCliSupportContent | null>(
      null
    );
    const [isDraft, setIsDraft] = useState(false);
    const [autoGenerateDescription, setAutoGenerateDescription] = useState(
      config?.pr_auto_description_enabled ?? false
    );
    const resetFormState = useCallback(() => {
      setPrTitle('');
      setPrBody('');
      setPrBaseBranch('');
      setCreatingPR(false);
      setError(null);
      setGhCliHelp(null);
      setIsDraft(false);
      setAutoGenerateDescription(config?.pr_auto_description_enabled ?? false);
    }, [config?.pr_auto_description_enabled]);

    const { data: branches = [], isLoading: branchesLoading } = useRepoBranches(
      repoId,
      { enabled: modal.visible && !!repoId }
    );

    useEffect(() => {
      if (!modal.visible) {
        resetFormState();
      }
    }, [modal.visible, resetFormState]);

    const getGhCliHelpTitle = (variant: GhCliSupportVariant) =>
      variant === 'homebrew'
        ? 'Homebrew is required for automatic setup'
        : 'GitHub CLI needs manual setup';

    // Initialize form when dialog opens
    useEffect(() => {
      if (!modal.visible || !isLoaded) {
        return;
      }

      let isCancelled = false;

      const initializePRFields = async () => {
        try {
          const firstUserMessage = await workspacesApi.getFirstUserMessage(
            attempt.id
          );

          if (isCancelled) return;

          if (firstUserMessage?.trim()) {
            const { title, description } =
              splitMessageToTitleDescription(firstUserMessage);
            setPrTitle(appendPrTitleSuffix(title));
            setPrBody(description ?? '');
            return;
          }
        } catch {
          // Fall back to empty fields if prompt loading fails.
        }

        if (isCancelled) return;
        setPrTitle('');
        setPrBody('');
      };

      initializePRFields();
      setError(null);
      setGhCliHelp(null);

      return () => {
        isCancelled = true;
      };
    }, [attempt.id, modal.visible, isLoaded, issueIdentifier]);

    // Set default base branch when branches are loaded
    useEffect(() => {
      if (!modal.visible || branches.length === 0) {
        return;
      }

      const hasSelectedBranch = prBaseBranch
        ? branches.some((branch) => branch.name === prBaseBranch)
        : false;

      if (hasSelectedBranch) {
        return;
      }

      if (
        targetBranch &&
        branches.some((branch) => branch.name === targetBranch)
      ) {
        setPrBaseBranch(targetBranch);
        return;
      }

      // Leave empty when target branch cannot be resolved; backend falls back to repo target branch.
      setPrBaseBranch('');
    }, [branches, modal.visible, prBaseBranch, targetBranch]);

    const isMacEnvironment = useMemo(
      () => environment?.os_type?.toLowerCase().includes('mac'),
      [environment?.os_type]
    );

    const handleConfirmCreatePR = useCallback(async () => {
      if (!repoId || !attempt.id) return;

      setError(null);
      setGhCliHelp(null);
      setCreatingPR(true);

      const handleGhCliSetupOutcome = (
        setupResult: GhCliSetupError | null,
        fallbackMessage: string
      ) => {
        if (setupResult === null) {
          setError(null);
          setGhCliHelp(null);
          setCreatingPR(false);
          modal.hide();
          return;
        }

        const ui = mapGhCliErrorToUi(setupResult, fallbackMessage, t);

        if (ui.variant) {
          setGhCliHelp(ui);
          setError(null);
          return;
        }

        setGhCliHelp(null);
        setError(ui.message);
      };

      const result = await workspacesApi.createPR(attempt.id, {
        title: prTitle,
        body: prBody || null,
        target_branch: prBaseBranch || null,
        draft: isDraft,
        auto_generate_description: autoGenerateDescription,
        repo_id: repoId,
      });

      if (result.success) {
        setCreatingPR(false);
        modal.resolve({ success: true } as CreatePRDialogResult);
        modal.hide();
        return;
      }

      setCreatingPR(false);

      const defaultGhCliErrorMessage =
        result.message || 'Failed to run GitHub CLI setup.';

      const showGhCliSetupDialog = async () => {
        const setupResult = await GhCliSetupDialog.show({
          workspaceId: attempt.id,
        });

        handleGhCliSetupOutcome(setupResult, defaultGhCliErrorMessage);
      };

      if (result.error) {
        if (
          result.error.type === 'cli_not_installed' ||
          result.error.type === 'cli_not_logged_in'
        ) {
          // Only show setup dialog for GitHub CLI on Mac
          if (result.error.provider === 'git_hub' && isMacEnvironment) {
            await showGhCliSetupDialog();
          } else {
            const providerName =
              result.error.provider === 'git_hub'
                ? 'GitHub'
                : result.error.provider === 'azure_dev_ops'
                  ? 'Azure DevOps'
                  : 'Git host';
            const action =
              result.error.type === 'cli_not_installed'
                ? 'not installed'
                : 'not logged in';
            setError(`${providerName} CLI is ${action}`);
            setGhCliHelp(null);
          }
          return;
        } else if (
          result.error.type === 'git_cli_not_installed' ||
          result.error.type === 'git_cli_not_logged_in'
        ) {
          const gitCliErrorKey =
            result.error.type === 'git_cli_not_logged_in'
              ? 'createPrDialog.errors.gitCliNotLoggedIn'
              : 'createPrDialog.errors.gitCliNotInstalled';

          setError(result.message || t(gitCliErrorKey));
          setGhCliHelp(null);
          return;
        } else if (result.error.type === 'target_branch_not_found') {
          setError(
            t('createPrDialog.errors.targetBranchNotFound', {
              branch: result.error.branch,
            })
          );
          setGhCliHelp(null);
          return;
        }
      }

      if (result.message) {
        setError(result.message);
        setGhCliHelp(null);
      } else {
        setError(t('createPrDialog.errors.failedToCreate'));
        setGhCliHelp(null);
      }
    }, [
      attempt,
      repoId,
      prBaseBranch,
      prBody,
      prTitle,
      isDraft,
      autoGenerateDescription,
      config?.pr_auto_description_enabled,
      modal,
      isMacEnvironment,
      t,
    ]);

    const handleCancelCreatePR = useCallback(() => {
      // Return error if one was set, otherwise just canceled
      const result: CreatePRDialogResult = error
        ? { success: false, error }
        : { success: false };
      modal.resolve(result);
      modal.hide();
    }, [modal, error]);

    return (
      <>
        <Dialog
          open={modal.visible}
          onOpenChange={(open) => {
            if (!open) {
              handleCancelCreatePR();
            }
          }}
        >
          <DialogContent className="sm:max-w-[525px]">
            <DialogHeader>
              <DialogTitle>{t('createPrDialog.title')}</DialogTitle>
              <DialogDescription>
                {t('createPrDialog.description')}
              </DialogDescription>
            </DialogHeader>
            {!isLoaded ? (
              <div className="flex justify-center py-8">
                <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
              </div>
            ) : (
              <div className="space-y-4 py-4">
                <div className="flex items-center space-x-2">
                  <Checkbox
                    id="pr-auto-generate"
                    checked={autoGenerateDescription}
                    onCheckedChange={setAutoGenerateDescription}
                    className="h-5 w-5"
                  />
                  <Label
                    htmlFor="pr-auto-generate"
                    className="cursor-pointer text-sm"
                  >
                    {t('createPrDialog.autoGenerateLabel')}
                  </Label>
                </div>
                <div className="space-y-2">
                  <Label htmlFor="pr-title">
                    {t('createPrDialog.titleLabel')}
                  </Label>
                  <Input
                    id="pr-title"
                    value={prTitle}
                    onChange={(e) => setPrTitle(e.target.value)}
                    placeholder={t('createPrDialog.titlePlaceholder')}
                    disabled={autoGenerateDescription}
                    className={
                      autoGenerateDescription
                        ? 'opacity-50 cursor-not-allowed'
                        : ''
                    }
                  />
                </div>
                <div className="space-y-2">
                  <Label htmlFor="pr-body">
                    {t('createPrDialog.descriptionLabel')}
                  </Label>
                  <Textarea
                    id="pr-body"
                    value={prBody}
                    onChange={(e) => setPrBody(e.target.value)}
                    placeholder={t('createPrDialog.descriptionPlaceholder')}
                    rows={4}
                    disabled={autoGenerateDescription}
                    className={
                      autoGenerateDescription
                        ? 'opacity-50 cursor-not-allowed'
                        : ''
                    }
                  />
                </div>
                <div className="space-y-2">
                  <Label htmlFor="pr-base">
                    {t('createPrDialog.baseBranchLabel')}
                  </Label>
                  <BranchSelector
                    branches={branches}
                    selectedBranch={prBaseBranch}
                    onBranchSelect={setPrBaseBranch}
                    placeholder={
                      branchesLoading
                        ? t('createPrDialog.loadingBranches')
                        : t('createPrDialog.selectBaseBranch')
                    }
                    className={
                      branchesLoading ? 'opacity-50 cursor-not-allowed' : ''
                    }
                  />
                </div>
                <div className="flex items-center space-x-2">
                  <Checkbox
                    id="pr-draft"
                    checked={isDraft}
                    onCheckedChange={setIsDraft}
                    className="h-5 w-5"
                  />
                  <Label htmlFor="pr-draft" className="cursor-pointer text-sm">
                    {t('createPrDialog.draftLabel')}
                  </Label>
                </div>
                {ghCliHelp?.variant && (
                  <Alert variant="default">
                    <AlertTitle>
                      {getGhCliHelpTitle(ghCliHelp.variant)}
                    </AlertTitle>
                    <AlertDescription className="space-y-3">
                      <p>{ghCliHelp.message}</p>
                      <GhCliHelpInstructions
                        variant={ghCliHelp.variant}
                        t={t}
                      />
                    </AlertDescription>
                  </Alert>
                )}
                {error && <Alert variant="destructive">{error}</Alert>}
              </div>
            )}
            <DialogFooter>
              <Button variant="outline" onClick={handleCancelCreatePR}>
                {t('common:buttons.cancel')}
              </Button>
              <Button
                onClick={handleConfirmCreatePR}
                disabled={creatingPR || !prTitle.trim()}
                className="bg-blue-600 hover:bg-blue-700"
              >
                {creatingPR ? (
                  <>
                    <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                    {t('createPrDialog.creating')}
                  </>
                ) : (
                  t('createPrDialog.createButton')
                )}
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>
      </>
    );
  }
);

export const CreatePRDialog = defineModal<
  CreatePRDialogProps,
  CreatePRDialogResult
>(CreatePRDialogImpl);
