'use client';
import { formatErrorBanner } from '@/lib/api/toast-error';

import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetFooter } from '@/components/ui/sheet';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { UserPermissionMatrix } from './user-permission-matrix';
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { PhoneInput, type PhoneInputValue } from '@/components/shared/phone-input';
import { apiFetch } from '@/lib/api/client';
import { formatRole, NON_ASSIGNABLE_ROLE_NAMES } from '@/lib/constants';

interface Role {
  id: string;
  name: string;
}

interface UserFormProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  user?: {
    userId: string;
    displayName: string;
    fullName?: string | null;
    firstName?: string | null;
    lastName?: string | null;
    email: string;
    signingEmail?: string | null;
    phone: string | null;
    isActive: boolean;
    role: { id: string; name: string };
    residentialAccess?: boolean;
  } | null;
  onSuccess: () => void;
}

export function UserForm(props: UserFormProps) {
  return (
    <UserFormBody key={props.open ? `open:${props.user?.userId ?? 'new'}` : 'closed'} {...props} />
  );
}

function UserFormBody({ open, onOpenChange, user, onSuccess }: UserFormProps) {
  // Derive initial first/last names from the user payload.
  const initialNames = (() => {
    if (!user) return { first: '', last: '' };
    if (user.firstName || user.lastName) {
      return { first: user.firstName ?? '', last: user.lastName ?? '' };
    }
    const source = user.fullName ?? user.displayName;
    const parts = source.split(/\s+/);
    return { first: parts[0] ?? '', last: parts.slice(1).join(' ') };
  })();
  // useQuery replaces the prior useEffect(fetch+setRoles) pattern.
  const rolesQuery = useQuery<{ data: Role[] }>({
    queryKey: ['admin', 'roles'],
    queryFn: () => apiFetch('/api/v1/admin/roles'),
    enabled: open,
  });
  const roles = rolesQuery.data?.data ?? [];
  // Hide retired/owner-only system roles from the picker, but always keep the
  // role the user being edited already holds so their record stays editable.
  const selectableRoles = roles.filter(
    (r) => !NON_ASSIGNABLE_ROLE_NAMES.has(r.name) || r.id === user?.role.id,
  );
  const [firstName, setFirstName] = useState(initialNames.first);
  const [lastName, setLastName] = useState(initialNames.last);
  const [email, setEmail] = useState(user?.email ?? '');
  const [originalEmail] = useState(user?.email ?? '');
  const [emailConfirmOpen, setEmailConfirmOpen] = useState(false);
  // Optional signing-identity override (edit-only). The address that
  // represents this user in signing contexts (EOI signer slot, signing
  // notifications, "awaiting my signature" tab) without changing their login.
  const [signingEmail, setSigningEmail] = useState(user?.signingEmail ?? '');
  const [originalSigningEmail] = useState(user?.signingEmail ?? '');
  const [password, setPassword] = useState('');
  // New users: email them a set-password link by default rather than typing a
  // password here. Toggle off to set one manually.
  const [sendSetupEmail, setSendSetupEmail] = useState(true);
  const [displayName, setDisplayName] = useState(user?.displayName ?? '');
  // New users: optional sign-in username (they can also sign in with their
  // email). Lowercased on the way out; the API validates shape + uniqueness.
  const [username, setUsername] = useState('');
  const [phoneValue, setPhoneValue] = useState<PhoneInputValue | null>(
    user?.phone ? { e164: user.phone, country: 'US' } : null,
  );
  const [roleId, setRoleId] = useState(user?.role.id ?? '');
  const [isActive, setIsActive] = useState(user?.isActive ?? true);
  const [residentialAccess, setResidentialAccess] = useState(user?.residentialAccess ?? false);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const isEdit = !!user;
  const fullName = `${firstName} ${lastName}`.trim();

  function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    // Admin email change for an existing user goes through a confirmation
    // dialog because it locks the original sign-in identity out - the
    // submit path runs after the admin acknowledges. New-user creation
    // and same-email saves go straight through.
    if (isEdit && email.trim().toLowerCase() !== originalEmail.toLowerCase()) {
      setEmailConfirmOpen(true);
      return;
    }
    void persist();
  }

  async function persist() {
    setError(null);
    setLoading(true);
    const phoneE164 = phoneValue?.e164 ?? null;

    try {
      if (isEdit) {
        const emailChanged = email.trim().toLowerCase() !== originalEmail.toLowerCase();
        await apiFetch(`/api/v1/admin/users/${user.userId}`, {
          method: 'PATCH',
          body: {
            firstName: firstName || null,
            lastName: lastName || null,
            fullName: fullName || displayName,
            displayName,
            email: emailChanged ? email.trim() : undefined,
            // Send the signing override only when it changed. Empty string is
            // the explicit "clear it" sentinel the API understands.
            signingEmail:
              signingEmail.trim().toLowerCase() !== originalSigningEmail.toLowerCase()
                ? signingEmail.trim().toLowerCase()
                : undefined,
            phone: phoneE164,
            roleId,
            isActive,
            residentialAccess,
            notifyEmailChange: emailChanged ? true : undefined,
          },
        });
      } else {
        await apiFetch('/api/v1/admin/users', {
          method: 'POST',
          body: {
            name: fullName || displayName,
            firstName: firstName || null,
            lastName: lastName || null,
            email,
            // Email mode omits the password entirely; manual mode sends it.
            password: sendSetupEmail ? undefined : password,
            sendSetupEmail,
            displayName,
            username: username.trim() ? username.trim().toLowerCase() : undefined,
            phone: phoneE164 ?? undefined,
            roleId,
            residentialAccess,
          },
        });
      }
      onSuccess();
      onOpenChange(false);
    } catch (err: unknown) {
      const message = formatErrorBanner(err);
      setError(message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <Sheet open={open} onOpenChange={onOpenChange}>
      <SheetContent className="overflow-y-auto">
        <SheetHeader>
          <SheetTitle>{isEdit ? 'Edit User' : 'New User'}</SheetTitle>
        </SheetHeader>

        <Tabs defaultValue="profile" className="mt-6">
          <TabsList className="w-full">
            <TabsTrigger value="profile" className="flex-1">
              Profile &amp; role
            </TabsTrigger>
            <TabsTrigger value="permissions" className="flex-1" disabled={!isEdit}>
              Permissions
            </TabsTrigger>
          </TabsList>

          <TabsContent value="permissions" className="mt-4">
            {isEdit ? (
              <UserPermissionMatrix userId={user.userId} />
            ) : (
              <p className="text-sm text-muted-foreground">
                Save the new user first, then return here to fine-tune their permissions.
              </p>
            )}
          </TabsContent>

          <TabsContent value="profile" className="mt-4">
            <form onSubmit={handleSubmit} className="space-y-4">
              <div className="grid grid-cols-2 gap-3">
                <div className="space-y-2">
                  <Label htmlFor="user-first-name">First name</Label>
                  <Input
                    id="user-first-name"
                    value={firstName}
                    onChange={(e) => setFirstName(e.target.value)}
                    placeholder="Jane"
                    required
                  />
                </div>
                <div className="space-y-2">
                  <Label htmlFor="user-last-name">Last name</Label>
                  <Input
                    id="user-last-name"
                    value={lastName}
                    onChange={(e) => setLastName(e.target.value)}
                    placeholder="Doe"
                    required
                  />
                </div>
              </div>

              <div className="space-y-2">
                <Label htmlFor="user-display-name">Display name</Label>
                <Input
                  id="user-display-name"
                  value={displayName}
                  onChange={(e) => setDisplayName(e.target.value)}
                  placeholder={fullName || 'Jane Doe'}
                  required
                />
                <p className="text-xs text-muted-foreground">
                  How this user appears across the app - usually their full name, but they can pick
                  a nickname.
                </p>
              </div>

              {!isEdit && (
                <div className="space-y-2">
                  <Label htmlFor="user-username">Username (optional)</Label>
                  <Input
                    id="user-username"
                    value={username}
                    onChange={(e) => setUsername(e.target.value)}
                    placeholder="e.g. abbie"
                    autoCapitalize="none"
                    autoCorrect="off"
                    spellCheck={false}
                  />
                  <p className="text-xs text-muted-foreground">
                    Lets them sign in with a short username instead of their email. 2–30 lowercase
                    letters, digits, dot, underscore, or hyphen. Leave blank to sign in by email
                    only.
                  </p>
                </div>
              )}

              <div className="space-y-2">
                <Label htmlFor="user-email">Email</Label>
                <Input
                  id="user-email"
                  type="email"
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  placeholder="user@example.com"
                  required
                />
                {isEdit && email.trim().toLowerCase() !== originalEmail.toLowerCase() ? (
                  <p className="text-xs text-amber-600">
                    You&apos;ll be asked to confirm - the original address will receive an automated
                    notice that you, the admin, changed their sign-in email.
                  </p>
                ) : isEdit ? (
                  <p className="text-xs text-muted-foreground">
                    Changing this address is an admin-only override; the user will be notified at
                    the old address.
                  </p>
                ) : null}
              </div>

              {isEdit && (
                <div className="space-y-2">
                  <Label htmlFor="user-signing-email">Signing email (optional)</Label>
                  <Input
                    id="user-signing-email"
                    type="email"
                    value={signingEmail}
                    onChange={(e) => setSigningEmail(e.target.value)}
                    placeholder="e.g. sales@portnimara.com"
                    autoCapitalize="none"
                    autoCorrect="off"
                    spellCheck={false}
                  />
                  <p className="text-xs text-muted-foreground">
                    The address used to represent this user in document signing (signer slot,
                    signing notifications, &ldquo;awaiting my signature&rdquo; tab). Lets them sign
                    on behalf of a shared mailbox while keeping their own sign-in email. Leave blank
                    to sign as their login email.
                  </p>
                </div>
              )}

              {!isEdit && (
                <>
                  <div className="flex items-center justify-between rounded-lg border p-3">
                    <div>
                      <Label htmlFor="user-setup-email">Email a set-password link</Label>
                      <p className="text-xs text-muted-foreground">
                        The user gets an email to choose their own password. Turn off to set one
                        here instead.
                      </p>
                    </div>
                    <Switch
                      id="user-setup-email"
                      checked={sendSetupEmail}
                      onCheckedChange={setSendSetupEmail}
                    />
                  </div>

                  {!sendSetupEmail && (
                    <div className="space-y-2">
                      <Label htmlFor="user-password">Password</Label>
                      <Input
                        id="user-password"
                        type="password"
                        value={password}
                        onChange={(e) => setPassword(e.target.value)}
                        placeholder="Min 12 characters"
                        minLength={12}
                        required
                      />
                    </div>
                  )}
                </>
              )}

              <div className="space-y-2">
                <Label htmlFor="user-phone">Phone</Label>
                <PhoneInput
                  id="user-phone"
                  value={phoneValue}
                  onChange={setPhoneValue}
                  placeholder="Phone number"
                />
              </div>

              <div className="space-y-2">
                <Label htmlFor="user-role">Role</Label>
                <Select value={roleId} onValueChange={setRoleId} required>
                  <SelectTrigger id="user-role">
                    <SelectValue placeholder="Select a role" />
                  </SelectTrigger>
                  <SelectContent>
                    {selectableRoles.map((r) => (
                      <SelectItem key={r.id} value={r.id}>
                        {formatRole(r.name)}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>

              <div className="flex items-center justify-between rounded-lg border p-3">
                <div>
                  <Label htmlFor="user-residential">Residential access</Label>
                  <p className="text-xs text-muted-foreground">
                    Grant this user access to residential clients and interests in addition to their
                    primary role.
                  </p>
                </div>
                <Switch
                  id="user-residential"
                  checked={residentialAccess}
                  onCheckedChange={setResidentialAccess}
                />
              </div>

              {isEdit && (
                <div className="flex items-center justify-between rounded-lg border p-3">
                  <div>
                    <Label htmlFor="user-active">Account active</Label>
                    <p className="text-xs text-muted-foreground">Disabled users cannot sign in.</p>
                  </div>
                  <Switch id="user-active" checked={isActive} onCheckedChange={setIsActive} />
                </div>
              )}

              {error && <p className="whitespace-pre-line text-sm text-destructive">{error}</p>}

              <SheetFooter>
                <Button
                  type="button"
                  variant="outline"
                  onClick={() => onOpenChange(false)}
                  disabled={loading}
                >
                  Cancel
                </Button>
                <Button type="submit" disabled={loading || !displayName.trim() || !roleId}>
                  {loading ? 'Saving…' : isEdit ? 'Save changes' : 'Create user'}
                </Button>
              </SheetFooter>
            </form>
          </TabsContent>
        </Tabs>

        <AlertDialog open={emailConfirmOpen} onOpenChange={setEmailConfirmOpen}>
          <AlertDialogContent>
            <AlertDialogHeader>
              <AlertDialogTitle>Change this user&apos;s sign-in email?</AlertDialogTitle>
              <AlertDialogDescription>
                You&apos;re about to change <span className="font-medium">{originalEmail}</span> to{' '}
                <span className="font-medium">{email}</span>. From now on, they must sign in with
                the new address. The original address will receive an automated notification
                explaining that an administrator made the change.
              </AlertDialogDescription>
            </AlertDialogHeader>
            <AlertDialogFooter>
              <AlertDialogCancel disabled={loading}>Cancel</AlertDialogCancel>
              <AlertDialogAction
                onClick={(e) => {
                  e.preventDefault();
                  setEmailConfirmOpen(false);
                  void persist();
                }}
                disabled={loading}
              >
                Confirm change
              </AlertDialogAction>
            </AlertDialogFooter>
          </AlertDialogContent>
        </AlertDialog>
      </SheetContent>
    </Sheet>
  );
}
