"use client";

import type { ManagedUser, Role } from "@domainops/shared-types";
import { App, Button, Input, Popconfirm, Switch, Table, Tag, Tooltip, Typography } from "antd";
import {
  CheckCircleOutlined,
  CrownFilled,
  EditOutlined,
  KeyOutlined,
  PlusOutlined,
  PoweroffOutlined,
  SafetyCertificateOutlined,
  SafetyOutlined,
  SearchOutlined,
  StopOutlined,
} from "@ant-design/icons";
import type { ColumnsType, TablePaginationConfig } from "antd/es/table";
import type { FilterValue, SorterResult } from "antd/es/table/interface";
import { useCallback, useEffect, useState } from "react";
import {
  deactivateUser,
  forceLogoutUser,
  listRoles,
  listUsers,
  reactivateUser,
  resetUser2fa,
  resetUserPassword,
} from "@/lib/api/users";
import { ApiError } from "@/lib/api/client";
import { useAuth } from "@/lib/auth/AuthProvider";
import { PAGE_SIZE_OPTIONS, useServerPagination } from "@/lib/hooks/useServerPagination";
import { titleCase } from "@/lib/utils/text";
import { PageGuide } from "@/components/features/PageGuide";
import { USERS_GUIDES } from "@/lib/guides/users";
import { AddUserModal } from "./AddUserModal";
import { EditUserModal } from "./EditUserModal";
import { ManageRolesModal } from "./ManageRolesModal";

export default function UsersPage() {
  const { message, modal } = App.useApp();
  const { user: currentUser } = useAuth();
  const [users, setUsers] = useState<ManagedUser[]>([]);
  const [total, setTotal] = useState(0);
  const [roles, setRoles] = useState<Role[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [search, setSearch] = useState("");
  const [sortField, setSortField] = useState<string>("name");
  const [sortOrder, setSortOrder] = useState<"ascend" | "descend">("ascend");
  const { page, pageSize, resetToFirstPage, setPage, setPageSize } = useServerPagination();
  const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
  const [isAddOpen, setIsAddOpen] = useState(false);
  const [isManageRolesOpen, setIsManageRolesOpen] = useState(false);
  const [editingUser, setEditingUser] = useState<ManagedUser | null>(null);
  const [togglingId, setTogglingId] = useState<number | null>(null);
  const [resettingId, setResettingId] = useState<number | null>(null);
  const [resetting2faId, setResetting2faId] = useState<number | null>(null);
  const [forceLoggingOutId, setForceLoggingOutId] = useState<number | null>(null);
  const [isBulkWorking, setIsBulkWorking] = useState(false);

  // A crowned admin's own action_permissions resolve to a literal ["*"] (see
  // authPayload()), same as canDo() checks server-side - a plain .includes()
  // on the specific action string would miss that wildcard, so it's checked
  // explicitly here too, not just is_admin.
  const hasAction = (action: string) =>
    currentUser?.is_admin || (currentUser?.action_permissions ?? []).some((a) => a === "*" || a === action);
  const canResetPasswords = hasAction("user.password_reset");
  const canReset2fa = hasAction("user.2fa_reset");
  const canForceLogout = hasAction("user.force_logout");

  const load = useCallback(async () => {
    setIsLoading(true);
    try {
      const [usersPage, roleList] = await Promise.all([
        listUsers({ search, page, per_page: pageSize, sort: sortField, order: sortOrder }),
        listRoles(),
      ]);
      setUsers(usersPage.data);
      setTotal(usersPage.meta.total);
      setRoles(roleList);
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't load users.");
    } finally {
      setIsLoading(false);
    }
  }, [search, page, pageSize, sortField, sortOrder, message]);

  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void load();
  }, [load]);

  const selectedUsers = users.filter((u) => selectedRowKeys.includes(u.id) && u.id !== currentUser?.id);

  function handleTableChange(
    pagination: TablePaginationConfig,
    _filters: Record<string, FilterValue | null>,
    sorter: SorterResult<ManagedUser> | SorterResult<ManagedUser>[],
  ) {
    const nextPageSize = pagination.pageSize ?? pageSize;
    if (nextPageSize !== pageSize) {
      setPageSize(nextPageSize);
      setPage(1);
    } else {
      setPage(pagination.current ?? 1);
    }

    const activeSorter = Array.isArray(sorter) ? sorter[0] : sorter;
    if (activeSorter?.order) {
      setSortField(String(activeSorter.columnKey ?? activeSorter.field ?? "name"));
      setSortOrder(activeSorter.order);
    } else {
      setSortField("name");
      setSortOrder("ascend");
    }
    setSelectedRowKeys([]);
  }

  async function runBulk<T>(
    targets: ManagedUser[],
    action: (user: ManagedUser) => Promise<T>,
    successLabel: string,
  ) {
    setIsBulkWorking(true);
    try {
      const results = await Promise.allSettled(targets.map((u) => action(u).then((result) => ({ user: u, result }))));
      const fulfilled = results.filter((r) => r.status === "fulfilled") as PromiseFulfilledResult<{
        user: ManagedUser;
        result: T;
      }>[];
      const failed = results.length - fulfilled.length;

      if (fulfilled.length > 0) {
        message.success(`${successLabel} for ${fulfilled.length} user${fulfilled.length === 1 ? "" : "s"}.`);
      }
      if (failed > 0) {
        message.error(`Failed for ${failed} user${failed === 1 ? "" : "s"}.`);
      }

      setSelectedRowKeys([]);
      void load();
      return fulfilled.map((r) => r.value);
    } finally {
      setIsBulkWorking(false);
    }
  }

  async function handleBulkDeactivate() {
    const targets = selectedUsers.filter((u) => !u.deleted_at);
    await runBulk(targets, (u) => deactivateUser(u.id), "Deactivated");
  }

  async function handleBulkReactivate() {
    const targets = selectedUsers.filter((u) => u.deleted_at);
    await runBulk(targets, (u) => reactivateUser(u.id), "Reactivated");
  }

  async function handleBulkResetPassword() {
    const targets = selectedUsers;
    const outcomes = await runBulk(targets, (u) => resetUserPassword(u.id), "Password reset");
    if (outcomes.length === 0) return;

    modal.success({
      title: `${outcomes.length} password${outcomes.length === 1 ? "" : "s"} reset`,
      width: 480,
      content: (
        <div className="flex flex-col gap-2">
          <Typography.Text>Share these with each user now - they won&apos;t be shown again:</Typography.Text>
          {outcomes.map(({ user, result }) => (
            <div key={user.id} className="flex items-center justify-between gap-2">
              <Typography.Text>{user.name}</Typography.Text>
              <Typography.Text code copyable>
                {result.password}
              </Typography.Text>
            </div>
          ))}
        </div>
      ),
    });
  }

  async function handleBulkReset2fa() {
    await runBulk(selectedUsers, (u) => resetUser2fa(u.id), "Two-factor authentication reset");
  }

  async function handleBulkForceLogout() {
    await runBulk(selectedUsers, (u) => forceLogoutUser(u.id), "Force logged out");
  }

  async function handleToggleActive(target: ManagedUser, active: boolean) {
    setTogglingId(target.id);
    try {
      if (active) {
        await reactivateUser(target.id);
        message.success(`${target.name} reactivated.`);
      } else {
        await deactivateUser(target.id);
        message.success(`${target.name} deactivated.`);
      }
      void load();
    } catch (err) {
      message.error(
        err instanceof ApiError ? err.message : `Couldn't ${active ? "reactivate" : "deactivate"} that user.`,
      );
    } finally {
      setTogglingId(null);
    }
  }

  async function handleResetPassword(target: ManagedUser) {
    setResettingId(target.id);
    try {
      const { password } = await resetUserPassword(target.id);
      modal.success({
        title: `${target.name}'s password was reset`,
        content: (
          <div className="flex flex-col gap-2">
            <Typography.Text>Share this with them now - it won&apos;t be shown again:</Typography.Text>
            <Typography.Text code copyable className="text-base">
              {password}
            </Typography.Text>
          </div>
        ),
      });
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't reset that password.");
    } finally {
      setResettingId(null);
    }
  }

  async function handleReset2fa(target: ManagedUser) {
    setResetting2faId(target.id);
    try {
      await resetUser2fa(target.id);
      message.success(`Two-factor authentication reset for ${target.name}.`);
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't reset two-factor authentication.");
    } finally {
      setResetting2faId(null);
    }
  }

  async function handleForceLogout(target: ManagedUser) {
    setForceLoggingOutId(target.id);
    try {
      await forceLogoutUser(target.id);
      message.success(`${target.name} will be signed out on their next request.`);
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't force logout that user.");
    } finally {
      setForceLoggingOutId(null);
    }
  }

  const columns: ColumnsType<ManagedUser> = [
    {
      title: "Name",
      dataIndex: "name",
      key: "name",
      sorter: true,
      sortOrder: sortField === "name" ? sortOrder : null,
      render: (v: string) => <span className="font-semibold">{v}</span>,
    },
    {
      title: "Username",
      dataIndex: "username",
      key: "username",
      sorter: true,
      sortOrder: sortField === "username" ? sortOrder : null,
      render: (v: string) => <span className="font-mono">{v}</span>,
    },
    {
      title: "Email",
      dataIndex: "email",
      key: "email",
      sorter: true,
      sortOrder: sortField === "email" ? sortOrder : null,
    },
    {
      title: "Role",
      render: (_, u) => (
        <span className="flex items-center gap-1.5">
          {u.is_crowned && u.role?.label === "admin" ? "Admin (Crowned)" : titleCase(u.role?.label ?? "—")}
          {u.is_crowned && (
            <Tooltip title="Crowned Admin - works with full access, but can never touch a Super Admin">
              <Tag color="gold" icon={<CrownFilled />} className="!m-0" />
            </Tooltip>
          )}
        </span>
      ),
    },
    {
      title: "Status",
      key: "status",
      sorter: true,
      sortOrder: sortField === "status" ? sortOrder : null,
      render: (_, u) => (
        <Tooltip title={u.id === currentUser?.id ? "You can't deactivate your own account" : undefined}>
          <Switch
            checked={!u.deleted_at}
            loading={togglingId === u.id}
            disabled={u.id === currentUser?.id}
            onChange={(checked) => void handleToggleActive(u, checked)}
          />
        </Tooltip>
      ),
    },
    {
      title: "Actions",
      render: (_, u) => (
        <div className="flex gap-2">
          {currentUser?.is_crowned_or_above && (
            <Tooltip title="Edit user">
              <Button
                size="small"
                icon={<EditOutlined />}
                onClick={() => setEditingUser(u)}
                className="dms_users_edit_user_btn"
              />
            </Tooltip>
          )}
          {canResetPasswords && u.id !== currentUser?.id && (
            <Tooltip title="Reset Password">
              <Button
                size="small"
                icon={<KeyOutlined />}
                loading={resettingId === u.id}
                onClick={() => handleResetPassword(u)}
                className="dms_users_reset_password_btn"
              />
            </Tooltip>
          )}
          {canReset2fa && u.id !== currentUser?.id && (
            <Tooltip title="Reset 2FA">
              <Button
                size="small"
                icon={<SafetyCertificateOutlined />}
                loading={resetting2faId === u.id}
                onClick={() => handleReset2fa(u)}
                className="dms_users_reset_2fa_btn"
              />
            </Tooltip>
          )}
          {canForceLogout && u.id !== currentUser?.id && (
            <Popconfirm
              title="Force logout this user?"
              description={`${u.name} will be signed out immediately on their next request.`}
              onConfirm={() => handleForceLogout(u)}
            >
              <Tooltip title="Force Logout">
                <Button
                  size="small"
                  danger
                  icon={<PoweroffOutlined />}
                  loading={forceLoggingOutId === u.id}
                  className="dms_users_force_logout_btn"
                />
              </Tooltip>
            </Popconfirm>
          )}
        </div>
      ),
    },
  ];

  return (
    <div className="flex flex-col gap-4 page page-users">
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <Typography.Title level={4} style={{ margin: 0 }}>
            Users
          </Typography.Title>
          <PageGuide guides={USERS_GUIDES} label="Users guide" />
        </div>
        <div className="flex gap-2">
          {currentUser?.is_crowned_or_above && (
            <Button
              icon={<SafetyOutlined />}
              onClick={() => setIsManageRolesOpen(true)}
              className="dms_users_manage_access_btn"
            >
              Manage Feature Access
            </Button>
          )}
          <Button
            type="primary"
            icon={<PlusOutlined />}
            onClick={() => setIsAddOpen(true)}
            className="dms_users_add_user_btn"
          >
            Add User
          </Button>
        </div>
      </div>

      <Input.Search
        placeholder="Search by name, username, or email"
        allowClear
        prefix={<SearchOutlined />}
        style={{ maxWidth: 360 }}
        onSearch={(value) => {
          resetToFirstPage();
          setSearch(value);
        }}
      />

      {selectedRowKeys.length > 0 && (
        <div className="flex items-center gap-2 flex-wrap dms_users_bulk_bar">
          <Typography.Text>{selectedRowKeys.length} selected</Typography.Text>
          <Popconfirm title="Deactivate the selected users?" onConfirm={handleBulkDeactivate}>
            <Button size="small" icon={<StopOutlined />} loading={isBulkWorking} className="dms_users_bulk_deactivate_btn">
              Deactivate
            </Button>
          </Popconfirm>
          <Popconfirm title="Reactivate the selected users?" onConfirm={handleBulkReactivate}>
            <Button
              size="small"
              icon={<CheckCircleOutlined />}
              loading={isBulkWorking}
              className="dms_users_bulk_reactivate_btn"
            >
              Reactivate
            </Button>
          </Popconfirm>
          {canResetPasswords && (
            <Popconfirm title="Reset passwords for the selected users?" onConfirm={handleBulkResetPassword}>
              <Button size="small" icon={<KeyOutlined />} loading={isBulkWorking} className="dms_users_bulk_reset_password_btn">
                Reset Password
              </Button>
            </Popconfirm>
          )}
          {canReset2fa && (
            <Popconfirm title="Reset 2FA for the selected users?" onConfirm={handleBulkReset2fa}>
              <Button
                size="small"
                icon={<SafetyCertificateOutlined />}
                loading={isBulkWorking}
                className="dms_users_bulk_reset_2fa_btn"
              >
                Reset 2FA
              </Button>
            </Popconfirm>
          )}
          {canForceLogout && (
            <Popconfirm title="Force logout the selected users?" onConfirm={handleBulkForceLogout}>
              <Button
                size="small"
                danger
                icon={<PoweroffOutlined />}
                loading={isBulkWorking}
                className="dms_users_bulk_force_logout_btn"
              >
                Force Logout
              </Button>
            </Popconfirm>
          )}
          <Button size="small" onClick={() => setSelectedRowKeys([])} className="dms_users_bulk_clear_btn">
            Clear
          </Button>
        </div>
      )}

      <Table<ManagedUser>
        rowKey="id"
        columns={columns}
        dataSource={users}
        loading={isLoading}
        onChange={handleTableChange}
        rowSelection={{
          selectedRowKeys,
          onChange: (keys) => setSelectedRowKeys(keys as number[]),
          getCheckboxProps: (record) => ({ disabled: record.id === currentUser?.id }),
        }}
        pagination={{
          current: page,
          pageSize,
          total,
          showSizeChanger: true,
          pageSizeOptions: PAGE_SIZE_OPTIONS,
          showTotal: (count) => `${count} users`,
        }}
        className="dms_users_table"
      />

      <AddUserModal
        open={isAddOpen}
        roles={roles}
        onClose={() => setIsAddOpen(false)}
        onCreated={() => {
          setIsAddOpen(false);
          void load();
        }}
      />

      <EditUserModal
        open={!!editingUser}
        user={editingUser}
        roles={roles}
        onClose={() => setEditingUser(null)}
        onSaved={() => {
          setEditingUser(null);
          void load();
        }}
      />

      <ManageRolesModal
        open={isManageRolesOpen}
        roles={roles}
        users={users}
        onClose={() => setIsManageRolesOpen(false)}
        onSaved={() => {
          setIsManageRolesOpen(false);
          void load();
        }}
        onCrownChanged={() => void load()}
      />
    </div>
  );
}
