import { useMutation } from "@tanstack/react-query";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { CheckCircle2, KeyRound, Save, XCircle } from "lucide-react";
import {
  Button,
  Card,
  Group,
  PasswordInput,
  Stack,
  Text,
  Title,
} from "@mantine/core";
import { api } from "@/services/api";

/**
 * Mirrors IAM's own `IsStrongPassword` rule on ChangePasswordDto — minLength 8,
 * ≥1 lowercase, ≥1 number, ≥1 symbol, uppercase NOT required. Kept in step with
 * the server so the user gets a precise message inline instead of a generic 400.
 */
const strongPassword = z
  .string()
  .min(8, "At least 8 characters")
  .regex(/[a-z]/, "Include a lowercase letter")
  .regex(/\d/, "Include a number")
  .regex(/[^A-Za-z0-9]/, "Include a symbol");

const schema = z
  .object({
    oldPassword: z.string().min(1, "Current password is required"),
    newPassword: strongPassword,
    confirmPassword: z.string().min(1, "Confirm your new password"),
  })
  .refine((d) => d.newPassword === d.confirmPassword, {
    path: ["confirmPassword"],
    message: "Passwords do not match",
  })
  .refine((d) => d.newPassword !== d.oldPassword, {
    path: ["newPassword"],
    message: "New password must be different from your current one",
  });

type FormData = z.infer<typeof schema>;

/** IAM returns bare error codes; turn them into something a customer can act on. */
const MESSAGES: Record<string, string> = {
  unable_to_change_password: "Your current password is incorrect.",
  new_password_same_as_old:
    "New password must be different from your current one.",
  new_passwords_do_not_match: "The new passwords do not match.",
  user_credentials_not_found: "This account has no password set.",
};

/**
 * Password changes go straight to IAM's `PATCH /api/auth/change-password`, which
 * verifies the old password and owns the credential write (argon hashing,
 * retiring the previous credential). The freight app deliberately implements no
 * part of that — it only collects the fields.
 */
export default function ChangePasswordCard() {
  const {
    register,
    handleSubmit,
    reset,
    formState: { errors, isDirty },
  } = useForm<FormData>({
    resolver: zodResolver(schema),
    defaultValues: { oldPassword: "", newPassword: "", confirmPassword: "" },
  });

  const mutation = useMutation({
    mutationFn: (data: FormData) => api.auth.changePassword.call(data),
    // Never leave the old password sitting in component state after a change.
    onSuccess: () => reset(),
  });

  const errorMessage = (err: unknown): string => {
    const raw = (
      err as { response?: { data?: { message?: string | string[] } } }
    )?.response?.data?.message;
    const code = Array.isArray(raw) ? raw[0] : raw;
    if (!code) return "Could not change your password. Please try again.";
    return MESSAGES[code] ?? code;
  };

  return (
    <Card padding="lg">
      <Group gap="sm" mb="xs">
        <KeyRound size={20} />
        <Title order={3}>Password</Title>
      </Group>
      <Text c="edr-muted" size="sm" mb="lg">
        Change the password you use to sign in. You'll need your current one.
      </Text>

      <form onSubmit={handleSubmit((d) => mutation.mutate(d))}>
        <Stack gap="md">
          <PasswordInput
            label="Current Password"
            autoComplete="current-password"
            error={errors.oldPassword?.message}
            {...register("oldPassword")}
          />
          <PasswordInput
            label="New Password"
            description="At least 8 characters, with a lowercase letter, a number and a symbol."
            autoComplete="new-password"
            error={errors.newPassword?.message}
            {...register("newPassword")}
          />
          <PasswordInput
            label="Confirm New Password"
            autoComplete="new-password"
            error={errors.confirmPassword?.message}
            {...register("confirmPassword")}
          />
        </Stack>

        <Group
          justify="space-between"
          mt="xl"
          pt="md"
          style={{ borderTop: "1px solid var(--mantine-color-edr-border-0)" }}
        >
          <Group gap="xs">
            {mutation.isSuccess && (
              <Group gap={6} c="green">
                <CheckCircle2 size={16} />
                <Text size="sm" fw={500}>
                  Password changed
                </Text>
              </Group>
            )}
            {mutation.isError && (
              <Group gap={6} c="red">
                <XCircle size={16} />
                <Text size="sm" fw={500}>
                  {errorMessage(mutation.error)}
                </Text>
              </Group>
            )}
          </Group>
          <Group gap="md">
            <Button
              type="button"
              variant="outline"
              disabled={mutation.isPending || !isDirty}
              onClick={() => reset()}
            >
              Reset
            </Button>
            <Button
              type="submit"
              leftSection={<Save size={16} />}
              loading={mutation.isPending}
            >
              Change Password
            </Button>
          </Group>
        </Group>
      </form>
    </Card>
  );
}
