import { FormEvent, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

import { api } from "../../api/client";
import { Modal } from "../../components/Modal";
import { Page } from "../../components/Page";
import { Table } from "../../components/Table";

const columns = [
  { key: "name", label: "Group" },
  { key: "description", label: "Description" },
  { key: "members", label: "Members" },
  { key: "actions", label: "Actions" }
];

export function GroupsPage() {
  const queryClient = useQueryClient();
  const groupsQuery = useQuery({
    queryKey: ["groups"],
    queryFn: api.groups
  });
  const usersQuery = useQuery({
    queryKey: ["users"],
    queryFn: api.users
  });
  const [form, setForm] = useState({
    name: "",
    description: "",
    user_ids: [] as string[]
  });
  const [editingGroupId, setEditingGroupId] = useState<string | null>(null);
  const [editForm, setEditForm] = useState({
    name: "",
    description: "",
    user_ids: [] as string[]
  });

  const createMutation = useMutation({
    mutationFn: api.createGroup,
    onSuccess: () => {
      setForm({ name: "", description: "", user_ids: [] });
      void queryClient.invalidateQueries({ queryKey: ["groups"] });
    }
  });

  const updateMutation = useMutation({
    mutationFn: ({ groupId, payload }: { groupId: string; payload: typeof editForm }) => api.updateGroup(groupId, payload),
    onSuccess: () => {
      setEditingGroupId(null);
      setEditForm({ name: "", description: "", user_ids: [] });
      void queryClient.invalidateQueries({ queryKey: ["groups"] });
    }
  });

  const deleteMutation = useMutation({
    mutationFn: api.deleteGroup,
    onSuccess: () => {
      void queryClient.invalidateQueries({ queryKey: ["groups"] });
    }
  });

  const rows = groupsQuery.data?.map((group) => ({
    id: group.id,
    name: group.name,
    description: group.description || "-",
    members: group.members.length ? group.members.map((member) => member.username).join(", ") : "No members"
  })) ?? [];

  function toggleUser(userId: string, editing = false) {
    if (editing) {
      setEditForm((value) => ({
        ...value,
        user_ids: value.user_ids.includes(userId)
          ? value.user_ids.filter((id) => id !== userId)
          : [...value.user_ids, userId]
      }));
      return;
    }

    setForm((value) => ({
      ...value,
      user_ids: value.user_ids.includes(userId)
        ? value.user_ids.filter((id) => id !== userId)
        : [...value.user_ids, userId]
    }));
  }

  function onSubmit(event: FormEvent) {
    event.preventDefault();
    createMutation.mutate(form);
  }

  function startEdit(groupId: string) {
    const group = groupsQuery.data?.find((item) => item.id === groupId);
    if (!group) {
      return;
    }
    setEditingGroupId(groupId);
    setEditForm({
      name: group.name,
      description: group.description,
      user_ids: group.members.map((member) => member.id)
    });
  }

  function onEditSubmit(event: FormEvent) {
    event.preventDefault();
    if (!editingGroupId) {
      return;
    }
    updateMutation.mutate({
      groupId: editingGroupId,
      payload: editForm
    });
  }

  return (
    <Page
      title="Groups"
      subtitle="Bundle users into reusable access groups for policy assignment."
      actions={<span className="pill">Reusable targets</span>}
    >
      <form className="stacked-form card" onSubmit={onSubmit}>
        <div className="form-grid two">
          <input placeholder="group name" value={form.name} onChange={(event) => setForm((value) => ({ ...value, name: event.target.value }))} />
          <input placeholder="description" value={form.description} onChange={(event) => setForm((value) => ({ ...value, description: event.target.value }))} />
        </div>
        <div className="selection-panel">
          <p className="eyebrow">Members</p>
          <div className="selection-list">
            {(usersQuery.data ?? []).map((user) => (
              <label className="selection-item" key={user.id}>
                <input type="checkbox" checked={form.user_ids.includes(user.id)} onChange={() => toggleUser(user.id)} />
                <span>{user.username}</span>
              </label>
            ))}
          </div>
        </div>
        <div className="action-row">
          <button className="button" type="submit" disabled={createMutation.isPending}>Create group</button>
        </div>
      </form>
      {groupsQuery.isError ? <p className="notice">Unable to load groups from the API.</p> : null}
      {createMutation.isError ? <p className="notice">Unable to create group.</p> : null}
      {updateMutation.isError ? <p className="notice">Unable to update group.</p> : null}
      {deleteMutation.isError ? <p className="notice">Unable to delete group.</p> : null}
      <Table
        columns={columns}
        rows={rows}
        renderCell={(row, column) => {
          if (column.key === "actions") {
            return (
              <div className="action-row">
                <button className="ghost-button" type="button" onClick={() => startEdit(row.id)}>Edit</button>
                <button className="ghost-button" type="button" onClick={() => deleteMutation.mutate(row.id)}>Delete</button>
              </div>
            );
          }
          return <span>{row[column.key as keyof (typeof rows)[number]]}</span>;
        }}
      />
      {editingGroupId ? (
        <Modal title="Edit group" subtitle="Adjust members and details in one place." onClose={() => setEditingGroupId(null)}>
          <form className="stacked-form" onSubmit={onEditSubmit}>
            <input placeholder="group name" value={editForm.name} onChange={(event) => setEditForm((value) => ({ ...value, name: event.target.value }))} />
            <input placeholder="description" value={editForm.description} onChange={(event) => setEditForm((value) => ({ ...value, description: event.target.value }))} />
            <div className="selection-panel">
              <p className="eyebrow">Members</p>
              <div className="selection-list">
                {(usersQuery.data ?? []).map((user) => (
                  <label className="selection-item" key={user.id}>
                    <input type="checkbox" checked={editForm.user_ids.includes(user.id)} onChange={() => toggleUser(user.id, true)} />
                    <span>{user.username}</span>
                  </label>
                ))}
              </div>
            </div>
            <div className="action-row">
              <button className="button" type="submit" disabled={updateMutation.isPending}>Save group</button>
              <button className="ghost-button" type="button" onClick={() => setEditingGroupId(null)}>Cancel</button>
            </div>
          </form>
        </Modal>
      ) : null}
    </Page>
  );
}
