import { useState } from "react";
import { usePage } from "@inertiajs/react";
import Shell from "../components/Shell";
import {
    Badge,
    Button,
    Dialog,
    Empty,
    Errors,
    Field,
    Heading,
    Pagination,
    Panel,
    SaveForm,
    Search,
    Table,
} from "../components/ui";
import {
    person,
    type Assignment,
    type Options,
    type Paginated,
    type Shared,
    type Student,
    type User,
} from "../types";
function Editor({
    user,
    options,
    students,
    close,
}: {
    user: User | null;
    options: Options;
    students: Student[];
    close: () => void;
}) {
    const { roles } = usePage<Shared>().props;
    const [type, setType] = useState(user?.user_type ?? "staff");
    const [grants, setGrants] = useState<Assignment[]>(
        user?.assignments ?? [
            { role: "teacher", branch_id: null, department_id: null },
        ],
    );
    const change = (
        i: number,
        key: keyof Assignment,
        value: string | number | null,
    ) =>
        setGrants(grants.map((g, n) => (n === i ? { ...g, [key]: value } : g)));
    return (
        <Dialog
            title={user ? "Edit account and access" : "Create user account"}
            onClose={close}
        >
            <Errors />
            <SaveForm
                url={user ? `/users/${user.id}` : "/users"}
                method={user ? "put" : "post"}
                label={user ? "Save account" : "Create account"}
                onSuccess={close}
            >
                <div className="form-grid">
                    <Field label="Full name" name="name">
                        <input name="name" required defaultValue={user?.name} />
                    </Field>
                    <Field label="Email address" name="email">
                        <input
                            name="email"
                            type="email"
                            autoComplete="off"
                            required
                            defaultValue={user?.email}
                        />
                    </Field>
                    <Field label="User type">
                        <select
                            name="user_type"
                            value={type}
                            onChange={(e) =>
                                setType(e.target.value as "staff" | "student")
                            }
                        >
                            <option value="staff">Staff</option>
                            <option value="student">Student</option>
                        </select>
                    </Field>
                    <Field label="Account status">
                        <select
                            name="active"
                            defaultValue={user?.active === false ? "0" : "1"}
                        >
                            <option value="1">Active</option>
                            <option value="0">Inactive</option>
                        </select>
                    </Field>
                    <Field
                        label={
                            user
                                ? "New temporary password (optional)"
                                : "Temporary password"
                        }
                        name="password"
                        hint="At least 12 characters with letters and numbers."
                    >
                        <input
                            name="password"
                            type="password"
                            autoComplete="new-password"
                            required={!user}
                            minLength={12}
                        />
                    </Field>
                    <Field label="Confirm temporary password">
                        <input
                            name="password_confirmation"
                            type="password"
                            autoComplete="new-password"
                            required={!user}
                        />
                    </Field>
                </div>
                <input
                    type="hidden"
                    name="assignments"
                    value={JSON.stringify(
                        type === "student"
                            ? []
                            : grants.map((g) => ({
                                  role: g.role,
                                  branch_id: g.branch_id,
                                  department_id: g.department_id,
                              })),
                    )}
                />
                {type === "student" ? (
                    <Field label="Student record">
                        <select
                            name="student_id"
                            defaultValue={user?.student?.id ?? ""}
                            required
                        >
                            <option value="">Choose student</option>
                            {students
                                .filter(
                                    (s) => !s.user_id || s.user_id === user?.id,
                                )
                                .map((s) => (
                                    <option key={s.id} value={s.id}>
                                        {s.student_number} · {person(s)}
                                    </option>
                                ))}
                        </select>
                    </Field>
                ) : (
                    <>
                        <h3>Staff roles and scope</h3>
                        <p className="small">
                            Each assignment keeps its own branch and department
                            scope. Teaching also requires a class assignment.
                        </p>
                        {grants.map((g, i) => (
                            <div className="panel" key={i}>
                                <div className="form-grid">
                                    <Field label="Role">
                                        <select
                                            value={g.role}
                                            onChange={(e) => {
                                                const role = e.target.value;
                                                setGrants(
                                                    grants.map((v, n) =>
                                                        n === i
                                                            ? {
                                                                  role,
                                                                  branch_id:
                                                                      role ===
                                                                      "school_admin"
                                                                          ? null
                                                                          : v.branch_id,
                                                                  department_id:
                                                                      null,
                                                              }
                                                            : v,
                                                    ),
                                                );
                                            }}
                                        >
                                            {Object.entries(roles).map(
                                                ([key, r]) => (
                                                    <option
                                                        key={key}
                                                        value={key}
                                                    >
                                                        {r.label}
                                                    </option>
                                                ),
                                            )}
                                        </select>
                                    </Field>
                                    {g.role !== "school_admin" && (
                                        <Field label="Branch scope">
                                            <select
                                                value={g.branch_id ?? ""}
                                                onChange={(e) => {
                                                    const branch_id = e.target
                                                        .value
                                                        ? Number(e.target.value)
                                                        : null;
                                                    setGrants(
                                                        grants.map((v, n) =>
                                                            n === i
                                                                ? {
                                                                      ...v,
                                                                      branch_id,
                                                                      department_id:
                                                                          null,
                                                                  }
                                                                : v,
                                                        ),
                                                    );
                                                }}
                                            >
                                                <option value="">
                                                    All branches
                                                </option>
                                                {options.branches.map((b) => (
                                                    <option
                                                        key={b.id}
                                                        value={b.id}
                                                    >
                                                        {b.name}
                                                    </option>
                                                ))}
                                            </select>
                                        </Field>
                                    )}
                                    {[
                                        "department_monitor",
                                        "dean",
                                        "teacher",
                                    ].includes(g.role) && (
                                        <Field label="Department">
                                            <select
                                                value={g.department_id ?? ""}
                                                required={
                                                    g.role ===
                                                    "department_monitor"
                                                }
                                                onChange={(e) =>
                                                    change(
                                                        i,
                                                        "department_id",
                                                        e.target.value
                                                            ? Number(
                                                                  e.target
                                                                      .value,
                                                              )
                                                            : null,
                                                    )
                                                }
                                            >
                                                <option value="">
                                                    {g.role ===
                                                    "department_monitor"
                                                        ? "Choose department"
                                                        : "All departments in branch"}
                                                </option>
                                                {options.departments
                                                    .filter(
                                                        (d) =>
                                                            d.branch_id ===
                                                            g.branch_id,
                                                    )
                                                    .map((d) => (
                                                        <option
                                                            key={d.id}
                                                            value={d.id}
                                                        >
                                                            {d.name}
                                                        </option>
                                                    ))}
                                            </select>
                                        </Field>
                                    )}
                                </div>
                                <Button
                                    type="button"
                                    variant="ghost"
                                    onClick={() =>
                                        setGrants(
                                            grants.filter((_, n) => n !== i),
                                        )
                                    }
                                >
                                    Remove this role
                                </Button>
                            </div>
                        ))}
                        <Button
                            type="button"
                            variant="secondary"
                            icon="plus"
                            onClick={() =>
                                setGrants([
                                    ...grants,
                                    {
                                        role: "teacher",
                                        branch_id: null,
                                        department_id: null,
                                    },
                                ])
                            }
                        >
                            Add another role
                        </Button>
                    </>
                )}
            </SaveForm>
        </Dialog>
    );
}
export default function Users({
    users,
    options,
    students,
    search,
}: {
    users: Paginated<User>;
    options: Options;
    students: Student[];
    search: string;
}) {
    const [edit, setEdit] = useState<User | null | undefined>();
    const { roles } = usePage<Shared>().props;
    return (
        <Shell title="Users and access">
            <Heading
                title="Users and access"
                description="Create accounts, set user types and assign scoped staff responsibilities."
                action={
                    <Button icon="plus" onClick={() => setEdit(null)}>
                        Create user
                    </Button>
                }
            />
            <Panel>
                <Search
                    value={search}
                    url="/users"
                    placeholder="Search users"
                />
                {users.data.length ? (
                    <Table
                        columns={["User", "Type", "Access", "Status", "Action"]}
                    >
                        {users.data.map((u) => (
                            <tr key={u.id}>
                                <td>
                                    {u.name}
                                    <small>{u.email}</small>
                                </td>
                                <td>
                                    {u.user_type === "student"
                                        ? "Student"
                                        : "Staff"}
                                </td>
                                <td>
                                    {u.user_type === "student"
                                        ? u.student?.student_number
                                        : u.assignments
                                              .map(
                                                  (a) =>
                                                      `${roles[a.role]?.label} · ${a.branch?.name ?? "All branches"}${a.department ? ` · ${a.department.name}` : ""}`,
                                              )
                                              .join("; ")}
                                </td>
                                <td>
                                    <Badge
                                        tone={u.active ? "success" : "neutral"}
                                    >
                                        {u.active ? "Active" : "Inactive"}
                                    </Badge>
                                </td>
                                <td>
                                    <Button
                                        variant="secondary"
                                        onClick={() => setEdit(u)}
                                    >
                                        Edit access
                                    </Button>
                                </td>
                            </tr>
                        ))}
                    </Table>
                ) : (
                    <Empty title="No matching users" />
                )}
                <Pagination page={users} />
            </Panel>
            {edit !== undefined && (
                <Editor
                    user={edit}
                    options={options}
                    students={students}
                    close={() => setEdit(undefined)}
                />
            )}
        </Shell>
    );
}
