import { zodResolver } from "@hookform/resolvers/zod";
import {
  Button,
  Dialog,
  Field,
  Form,
  Input,
  Select,
  useNavigate,
} from "@tailor-platform/app-shell";
import { Eye, EyeOff, Copy } from "lucide-react";
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { useMutation, useQuery } from "urql";
import { z } from "zod";
import { graphql } from "@/graphql";
import { useToast } from "@/hooks/use-toast";

const RolesForSelectQuery = graphql(`
  query RolesForSelect {
    roles(order: [{ field: createdAt, direction: Desc }]) {
      edges {
        node {
          id
          name
        }
      }
    }
  }
`);

const CreateUserMutation = graphql(`
  mutation CreateUser($name: String!, $email: String!, $roleIds: [ID!]) {
    createUser(name: $name, email: $email, roleIds: $roleIds) {
      id
      name
      email
      status
      initialPassword
    }
  }
`);

const formSchema = z.object({
  name: z.string().min(1, "Name is required"),
  email: z.email("Invalid email address"),
  roleIds: z.array(z.string()),
});

type FormValues = z.infer<typeof formSchema>;

export const CreateUserForm = () => {
  const navigate = useNavigate();
  const toast = useToast();
  const [, createUser] = useMutation(CreateUserMutation);
  const [{ data: rolesData }] = useQuery({ query: RolesForSelectQuery });
  const [initialPassword, setInitialPassword] = useState<string | null>(null);
  const [showPassword, setShowPassword] = useState(false);

  const roles = rolesData?.roles.edges.map((edge) => edge.node) ?? [];

  const form = useForm<FormValues>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      name: "",
      email: "",
      roleIds: [],
    },
  });

  const onSubmit = (values: FormValues) => {
    void createUser(values, { additionalTypenames: ["User"] }).then((result) => {
      if (result.error) {
        toast.error(result.error);
        return;
      }
      setInitialPassword(result.data?.createUser.initialPassword ?? null);
    });
  };

  const onCancel = () => {
    void navigate("..");
  };

  return (
    <>
      <Form
        noValidate
        onSubmit={(e) => void form.handleSubmit(onSubmit)(e)}
        className="max-w-md space-y-4"
      >
        <Controller
          control={form.control}
          name="name"
          render={({ field, fieldState }) => (
            <Field.Root name={field.name} invalid={fieldState.invalid}>
              <Field.Label>Name</Field.Label>
              <Field.Control placeholder="Enter name" {...field} />
              {fieldState.error && <Field.Error match>{fieldState.error.message}</Field.Error>}
            </Field.Root>
          )}
        />
        <Controller
          control={form.control}
          name="email"
          render={({ field, fieldState }) => (
            <Field.Root name={field.name} invalid={fieldState.invalid}>
              <Field.Label>Email</Field.Label>
              <Field.Control
                inputMode="email"
                autoComplete="email"
                placeholder="Enter email"
                {...field}
              />
              {fieldState.error && <Field.Error match>{fieldState.error.message}</Field.Error>}
            </Field.Root>
          )}
        />
        <Controller
          control={form.control}
          name="roleIds"
          render={({ field, fieldState }) => (
            <Field.Root name={field.name} invalid={fieldState.invalid}>
              <Field.Label>Roles</Field.Label>
              <Select
                multiple
                items={roles}
                value={roles.filter((r) => field.value.includes(r.id))}
                onValueChange={(selected) => field.onChange(selected.map((r) => r.id))}
                mapItem={(role) => ({ label: role.name, key: role.id })}
                placeholder="Select roles"
              />
              {fieldState.error && <Field.Error match>{fieldState.error.message}</Field.Error>}
            </Field.Root>
          )}
        />
        <div className="flex gap-2">
          <Button type="submit">Create</Button>
          <Button type="button" variant="outline" onClick={onCancel}>
            Cancel
          </Button>
        </div>
      </Form>
      <Dialog.Root
        open={initialPassword !== null}
        onOpenChange={() => {
          // Only close via the Done button
        }}
      >
        <Dialog.Content>
          <Dialog.Header>
            <Dialog.Title>User Created</Dialog.Title>
            <Dialog.Description>
              The user has been created. Please copy the initial password and share it with the
              user. This password will not be shown again.
            </Dialog.Description>
          </Dialog.Header>
          <div className="flex items-center gap-2 py-4">
            <Input
              readOnly
              type={showPassword ? "text" : "password"}
              value={initialPassword ?? ""}
              className="flex-1"
            />
            <Button variant="ghost" size="icon" onClick={() => setShowPassword((prev) => !prev)}>
              {showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
            </Button>
            <Button
              variant="ghost"
              size="icon"
              onClick={() => {
                if (initialPassword) {
                  void navigator.clipboard.writeText(initialPassword);
                  toast.success("Password copied to clipboard");
                }
              }}
            >
              <Copy className="h-4 w-4" />
            </Button>
          </div>
          <Dialog.Footer>
            <Button
              onClick={() => {
                setInitialPassword(null);
                void navigate("..");
              }}
            >
              Done
            </Button>
          </Dialog.Footer>
        </Dialog.Content>
      </Dialog.Root>
    </>
  );
};
