'use client';

import { zodResolver } from '@hookform/resolvers/zod';
import { Button } from '@tale/ui/button';
import { Stack } from '@tale/ui/layout';
import { ConvexError } from 'convex/values';
import { useState, useMemo } from 'react';
import { useForm } from 'react-hook-form';
import * as z from 'zod';

import { CopyableField } from '@/app/components/ui/data-display/copyable-field';
import { FormDialog } from '@/app/components/ui/dialog/form-dialog';
import { ViewDialog } from '@/app/components/ui/dialog/view-dialog';
import { ValidationCheckList } from '@/app/components/ui/feedback/validation-check-item';
import { FormSection } from '@/app/components/ui/forms/form-section';
import { Input } from '@/app/components/ui/forms/input';
import { Select } from '@/app/components/ui/forms/select';
import { usePasswordPolicy } from '@/app/features/settings/governance/hooks/queries';
import { usePasswordValidation } from '@/app/hooks/use-password-validation';
import { useToast } from '@/app/hooks/use-toast';
import { useT } from '@/lib/i18n/client';
import { createOptionalPasswordSchema } from '@/lib/shared/schemas/password';
import { narrowStringUnion } from '@/lib/utils/type-guards';

import { useCreateMember } from '../hooks/mutations';

// Type for the form data
type AddMemberFormData = {
  email: string;
  password?: string;
  displayName?: string;
  role: 'disabled' | 'admin' | 'developer' | 'editor' | 'member';
};

interface AddMemberDialogProps {
  organizationId: string;
  open: boolean;
  onOpenChange: (open: boolean) => void;
}

// This is the primary way to add users to Tale. Since the platform is offline-first,
// there is no self-service sign-up — admins create accounts here with an email,
// optional password, and role. For self-service provisioning, configure SSO or
// trusted headers instead (see docs/authentication.md).
export function AddMemberDialog({
  organizationId,
  open,
  onOpenChange,
}: AddMemberDialogProps) {
  const { t: tDialogs } = useT('dialogs');
  const { t: tSettings } = useT('settings');
  const { t: tCommon } = useT('common');
  const { t: tAuth } = useT('auth');
  const { t: tToast } = useT('toast');

  const policy = usePasswordPolicy(organizationId);

  const addMemberSchema = useMemo(
    () =>
      z.object({
        email: z.string().email(tCommon('validation.email')),
        password: createOptionalPasswordSchema(
          {
            minLength: tAuth('validation.passwordMinLength', {
              n: policy.minLength,
            }),
            lowercase: tAuth('validation.passwordLowercase'),
            uppercase: tAuth('validation.passwordUppercase'),
            number: tAuth('validation.passwordNumber'),
            specialChar: tAuth('validation.passwordSpecial'),
          },
          policy,
        ),
        displayName: z.string().optional(),
        role: z.enum(['disabled', 'admin', 'developer', 'editor', 'member']),
      }),
    [tCommon, tAuth, policy],
  );

  const [showCredentials, setShowCredentials] = useState(false);
  const [isExistingUser, setIsExistingUser] = useState(false);
  const [credentials, setCredentials] = useState<{
    email: string;
    password: string;
  } | null>(null);
  const { toast } = useToast();

  const { mutateAsync: createMember, isPending: isSubmitting } =
    useCreateMember();
  const form = useForm<AddMemberFormData>({
    resolver: zodResolver(addMemberSchema),
    mode: 'onChange',
    defaultValues: {
      email: '',
      password: '',
      displayName: '',
      role: 'member',
    },
  });

  const {
    handleSubmit,
    register,
    reset,
    setValue,
    setError,
    watch,
    formState,
  } = form;
  const selectedRole = watch('role');
  const password = watch('password') ?? '';

  const passwordValidationItems = usePasswordValidation(password, policy);

  const onSubmit = async (data: AddMemberFormData) => {
    try {
      const result = await createMember({
        organizationId,
        email: data.email,
        password: data.password || undefined,
        displayName: data.displayName,
        role: data.role,
      });

      toast({
        title: result.isExistingUser
          ? tToast('success.existingUserAdded')
          : tToast('success.newMemberCreated'),
        variant: 'success',
      });

      if (result.isExistingUser) {
        setIsExistingUser(true);
        setShowCredentials(true);
      } else if (data.password) {
        setIsExistingUser(false);
        setCredentials({ email: data.email, password: data.password });
        setShowCredentials(true);
      } else {
        reset();
        onOpenChange(false);
      }
    } catch (error) {
      console.error(error);
      // A new user requires a password; surface it on the field rather than a
      // generic toast, so the user knows what to fix (#1470).
      if (
        error instanceof ConvexError &&
        error.data?.code === 'PASSWORD_REQUIRED'
      ) {
        setError('password', {
          message: tAuth('validation.passwordRequiredForNewUser'),
        });
        return;
      }
      toast({
        title: tToast('error.addMemberFailed'),
        variant: 'destructive',
      });
    }
  };

  const handleClose = () => {
    setShowCredentials(false);
    setIsExistingUser(false);
    setCredentials(null);
    reset();
    onOpenChange(false);
  };

  const handleOpenChange = (isOpen: boolean) => {
    if (!isOpen && !showCredentials) {
      reset();
    }
    onOpenChange(isOpen);
  };

  return (
    <>
      <FormDialog
        open={open && !showCredentials}
        onOpenChange={handleOpenChange}
        title={tDialogs('addMember.title')}
        submitText={tDialogs('addMember.title')}
        submittingText={tCommon('actions.adding')}
        isSubmitting={isSubmitting}
        isValid={formState.isValid}
        onSubmit={handleSubmit(onSubmit)}
      >
        <Input
          id="displayName"
          label={tSettings('form.name')}
          placeholder={tSettings('form.namePlaceholder')}
          {...register('displayName')}
          className="w-full"
        />

        <Input
          id="email"
          type="email"
          label={tSettings('form.email')}
          placeholder={tSettings('form.emailPlaceholder')}
          {...register('email')}
          className="w-full"
          required
          errorMessage={formState.errors.email?.message}
        />

        <Select
          value={selectedRole}
          onValueChange={(value) => {
            const narrowed = narrowStringUnion<
              'disabled' | 'admin' | 'developer' | 'editor' | 'member'
            >(value, [
              'disabled',
              'admin',
              'developer',
              'editor',
              'member',
            ] as const);
            if (narrowed) {
              setValue('role', narrowed, { shouldDirty: true });
            }
          }}
          label={tSettings('form.role')}
          options={[
            { value: 'admin', label: tSettings('roles.admin') },
            { value: 'developer', label: tSettings('roles.developer') },
            { value: 'editor', label: tSettings('roles.editor') },
            { value: 'member', label: tSettings('roles.member') },
            { value: 'disabled', label: tSettings('roles.disabled') },
          ]}
        />

        <FormSection>
          <Input
            id="password"
            type="password"
            autoComplete="new-password"
            label={tSettings('form.password')}
            placeholder={tSettings('form.passwordPlaceholder')}
            description={tSettings('form.forgotPassword')}
            {...register('password')}
            errorMessage={formState.errors.password?.message}
            className="w-full"
          />
          {password && (
            <ValidationCheckList
              items={passwordValidationItems}
              className="text-xs"
            />
          )}
        </FormSection>
      </FormDialog>

      <ViewDialog
        open={showCredentials}
        onOpenChange={handleClose}
        title={tDialogs('memberAdded.title')}
      >
        <Stack gap={4}>
          {isExistingUser ? (
            <div className="rounded-lg border border-blue-200 bg-blue-50 p-4 text-sm text-blue-800 dark:border-blue-800 dark:bg-blue-950/20 dark:text-blue-200">
              {tDialogs('memberAdded.existingUserNotice')}
            </div>
          ) : (
            <>
              <div className="rounded-lg border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800 dark:border-amber-800 dark:bg-amber-950/20 dark:text-amber-200">
                {tDialogs('memberAdded.credentialsWarning')}
              </div>

              {credentials && (
                <Stack gap={4}>
                  <CopyableField
                    value={credentials.email}
                    label={tSettings('form.email')}
                  />
                  <CopyableField
                    value={credentials.password}
                    label={tSettings('form.password')}
                  />
                </Stack>
              )}
            </>
          )}

          <Button onClick={handleClose} fullWidth>
            {tCommon('actions.done')}
          </Button>
        </Stack>
      </ViewDialog>
    </>
  );
}
