"use client";

import type { Role } from "@domainops/shared-types";
import { App, Button, Form, Input, Modal, Select, Typography } from "antd";
import { CopyOutlined, ReloadOutlined } from "@ant-design/icons";
import { useState } from "react";
import { createUser } from "@/lib/api/users";
import type { CreateUserInput } from "@/lib/api/users";
import { getPublicSettings } from "@/lib/api/settings";
import { reportFormErrors } from "@/lib/utils/formErrors";
import { titleCase } from "@/lib/utils/text";

const PASSWORD_CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#$%";

function generatePassword(length = 16): string {
  const values = new Uint32Array(length);
  window.crypto.getRandomValues(values);
  return Array.from(values, (v) => PASSWORD_CHARS[v % PASSWORD_CHARS.length]).join("");
}

interface NewUserCredentials {
  username: string;
  password: string;
  loginUrl: string;
}

export function AddUserModal({
  open,
  roles,
  onClose,
  onCreated,
}: {
  open: boolean;
  roles: Role[];
  onClose: () => void;
  onCreated: () => void;
}) {
  const { message } = App.useApp();
  const [form] = Form.useForm<CreateUserInput>();
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [credentials, setCredentials] = useState<NewUserCredentials | null>(null);

  function handleGeneratePassword() {
    const password = generatePassword();
    form.setFieldsValue({ password, password_confirmation: password });
  }

  async function handleSubmit(values: CreateUserInput) {
    setIsSubmitting(true);
    try {
      await createUser(values);
      message.success(`${values.name} added.`);
      const settings = await getPublicSettings().catch(() => null);
      setCredentials({
        username: values.username,
        password: values.password,
        loginUrl: `${window.location.origin}${settings?.login_url ?? "/login"}`,
      });
      form.resetFields();
      onCreated();
    } catch (err) {
      message.error(reportFormErrors(form, err, "Couldn't add that user."));
    } finally {
      setIsSubmitting(false);
    }
  }

  async function handleCopyCredentials() {
    if (!credentials) return;
    const text = `Login URL: ${credentials.loginUrl}\nUsername: ${credentials.username}\nPassword: ${credentials.password}`;
    try {
      await navigator.clipboard.writeText(text);
      message.success("Copied to clipboard.");
    } catch {
      message.error("Couldn't copy - your browser may be blocking clipboard access.");
    }
  }

  function handleCloseCredentials() {
    setCredentials(null);
    onClose();
  }

  if (credentials) {
    return (
      <Modal
        title="Share access with the new user"
        open={open}
        onCancel={handleCloseCredentials}
        footer={
          <Button type="primary" icon={<CopyOutlined />} onClick={handleCopyCredentials} className="dms_add_user_copy_credentials_btn">
            Copy to clipboard
          </Button>
        }
        destroyOnHidden
        className="dms_add_user_credentials_modal"
      >
        <Typography.Paragraph type="secondary">
          Mail isn&apos;t configured to send automatically - copy this and forward it to them yourself (email, chat,
          whatever they check).
        </Typography.Paragraph>
        <div className="flex flex-col gap-1 font-mono text-sm bg-gray-50 rounded p-3 dms_add_user_credentials_box">
          <span>Login URL: {credentials.loginUrl}</span>
          <span>Username: {credentials.username}</span>
          <span>Password: {credentials.password}</span>
        </div>
      </Modal>
    );
  }

  return (
    <Modal
      title="Add User"
      open={open}
      onCancel={onClose}
      onOk={() => form.submit()}
      confirmLoading={isSubmitting}
      okText="Add user"
      destroyOnHidden
      className="dms_add_user_modal"
    >
      <Form<CreateUserInput> form={form} layout="vertical" onFinish={handleSubmit} className="dms_add_user_form">
        <Form.Item
          name="name"
          label="Name"
          rules={[{ required: true, message: "Enter their name" }]}
          className="dms_add_user_name_field"
        >
          <Input autoFocus />
        </Form.Item>
        <Form.Item
          name="username"
          label="Username"
          rules={[{ required: true, message: "Pick a username" }]}
          className="dms_add_user_username_field"
        >
          <Input autoComplete="off" />
        </Form.Item>
        <Form.Item
          name="email"
          label="Email"
          rules={[
            { required: true, message: "Enter an email" },
            { type: "email", message: "Enter a valid email" },
          ]}
          className="dms_add_user_email_field"
        >
          <Input autoComplete="off" />
        </Form.Item>
        <Form.Item
          name="role_id"
          label="Role"
          rules={[{ required: true, message: "Pick a role" }]}
          className="dms_add_user_role_field"
        >
          <Select options={roles.map((r) => ({ value: r.id, label: titleCase(r.label) }))} />
        </Form.Item>
        <Form.Item
          name="password"
          label="Password"
          rules={[{ required: true, min: 8, message: "At least 8 characters" }]}
          className="dms_add_user_password_field"
          extra={
            <Button
              type="link"
              size="small"
              icon={<ReloadOutlined />}
              onClick={handleGeneratePassword}
              style={{ padding: 0 }}
              className="dms_add_user_generate_password_btn"
            >
              Generate a password
            </Button>
          }
        >
          <Input.Password autoComplete="new-password" visibilityToggle />
        </Form.Item>
        <Form.Item
          name="password_confirmation"
          label="Repeat password"
          dependencies={["password"]}
          rules={[
            { required: true, message: "Repeat the password" },
            ({ getFieldValue }) => ({
              validator(_, value) {
                if (!value || getFieldValue("password") === value) return Promise.resolve();
                return Promise.reject(new Error("Passwords do not match"));
              },
            }),
          ]}
          className="dms_add_user_password_confirmation_field"
        >
          <Input.Password autoComplete="new-password" visibilityToggle />
        </Form.Item>
      </Form>
    </Modal>
  );
}
