"use client";

import { useCallback, useEffect, useState, type FormEvent } from "react";
import { UserPlus } from "lucide-react";
import { Badge, Button, ConfirmDialog, Dialog, Field, Input, PageHeader, Panel, Select, Skeleton } from "@/components/ui/kit";
import { useToast } from "@/components/ui/toast";
import { useSession } from "@/components/session";
import { api, ApiError } from "@/lib/api";
import { formatDateTime, initials, ROLE_LABELS } from "@/lib/format";
import type { TeamMember } from "@/lib/types";

const OWNER_ROLES = ["customer_owner", "reseller"];

/** What each role can do, shown when adding someone or changing a role. */
const CUSTOMER_ROLES: { value: string; label: string; hint: string }[] = [
  { value: "customer_owner", label: "Owner", hint: "Everything, including the wallet, plan and payments, and managing other owners." },
  { value: "customer_admin", label: "Admin", hint: "Runs the workspace: WhatsApp, templates, campaigns, bots, contacts and the team. No billing changes." },
  { value: "customer_agent", label: "Agent", hint: "Works the inbox and contacts: replies, takes chats, adds and edits contacts. Can't delete, import or export." },
  { value: "customer_viewer", label: "Viewer", hint: "Can look at contacts, chats, campaigns and bots, but can't change anything." },
];
const RESELLER_ROLES = [
  { value: "customer_owner", label: "Owner", hint: "Manages customers, plan prices and the team." },
  { value: "customer_viewer", label: "Staff", hint: "Can see customers and earnings, but can't change anything." },
];

/** The form value for a stored role (reseller roles map onto the owner / staff choice). */
const formRole = (role: string) => (role === "reseller" ? "customer_owner" : role === "reseller_staff" ? "customer_viewer" : role);

function RoleSelect({ member, options, disabled, onChange }: { member: TeamMember; options: typeof CUSTOMER_ROLES; disabled: boolean; onChange: (role: string) => void }) {
  const [value, setValue] = useState(formRole(member.role));
  return (
    <Select
      aria-label={`Role for ${member.name}`}
      className="w-36"
      value={value}
      disabled={disabled}
      onChange={(e) => {
        setValue(e.target.value);
        onChange(e.target.value);
      }}
    >
      {options.map((o) => (
        <option key={o.value} value={o.value}>
          {o.label}
        </option>
      ))}
    </Select>
  );
}

export default function TeamPage() {
  const { can, me } = useSession();
  const toast = useToast();
  const [members, setMembers] = useState<TeamMember[] | null>(null);
  const [adding, setAdding] = useState(false);
  const [toRemove, setToRemove] = useState<TeamMember | null>(null);
  const [errors, setErrors] = useState<Record<string, string>>({});
  const [saving, setSaving] = useState(false);
  const [newRole, setNewRole] = useState("customer_agent");

  const isReseller = me?.organization?.type === "reseller";
  const options = isReseller ? RESELLER_ROLES : CUSTOMER_ROLES;
  const iAmOwner = OWNER_ROLES.includes(me?.role ?? "");
  const manage = can("team.manage");
  // Only owners can hand out the owner role.
  const grantable = options.filter((o) => iAmOwner || o.value !== "customer_owner");

  const load = useCallback(() => api.get<{ data: TeamMember[] }>("/team").then((r) => setMembers(r.data)), []);
  useEffect(() => {
    load().catch((e) => toast("error", e.message));
  }, [load, toast]);

  async function add(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setSaving(true);
    setErrors({});
    try {
      await api.post("/team", Object.fromEntries(new FormData(e.currentTarget)));
      toast("success", "Teammate added. Share their password with them securely.");
      setAdding(false);
      load();
    } catch (err) {
      if (err instanceof ApiError && Object.keys(err.fields).length) setErrors(err.fields);
      else toast("error", (err as Error).message);
    } finally {
      setSaving(false);
    }
  }

  async function changeRole(m: TeamMember, role: string) {
    try {
      await api.patch(`/team/${m.id}`, { role });
      toast("success", `${m.name} is now ${(options.find((o) => o.value === role)?.label ?? role).toLowerCase()}`);
    } catch (e) {
      toast("error", (e as Error).message);
    }
    load();
  }

  async function remove() {
    if (!toRemove) return;
    setSaving(true);
    try {
      await api.delete(`/team/${toRemove.id}`);
      toast("success", `${toRemove.name} removed from the team`);
      setToRemove(null);
      load();
    } catch (e) {
      toast("error", (e as Error).message);
    } finally {
      setSaving(false);
    }
  }

  return (
    <>
      <PageHeader
        title="Team"
        description={
          isReseller
            ? "People who can sign in to your reseller account. Owners manage customers and prices; staff can only look."
            : "People who can sign in to this workspace. Owners handle billing; admins run the workspace; agents work the inbox; viewers can only look."
        }
        actions={
          manage && (
            <Button
              variant="primary"
              icon={<UserPlus className="size-4" />}
              onClick={() => {
                setErrors({});
                setNewRole(isReseller ? "customer_viewer" : "customer_agent");
                setAdding(true);
              }}
            >
              Add teammate
            </Button>
          )
        }
      />
      <Panel>
        {!members ? (
          <div className="space-y-3 p-4">
            <Skeleton className="h-10 w-full" />
            <Skeleton className="h-10 w-full" />
          </div>
        ) : (
          <ul className="divide-y divide-line">
            {members.map((m) => {
              const self = m.id === me?.user.id;
              const ownerRow = OWNER_ROLES.includes(m.role);
              // Admins can't change or remove owners; nobody changes their own role.
              const editable = manage && !self && (iAmOwner || !ownerRow);
              return (
                <li key={`${m.id}-${m.role}`} className="flex flex-wrap items-center gap-x-4 gap-y-2 px-4 py-3">
                  <span className="grid size-9 place-items-center rounded-full bg-teal-soft text-sm font-semibold text-teal">{initials(m.name)}</span>
                  <div className="min-w-0 flex-1 basis-48">
                    <div className="font-medium text-ink">
                      {m.name}
                      {self && <span className="ml-2 text-xs font-normal text-muted">(you)</span>}
                    </div>
                    <div className="truncate text-sm text-muted">{m.email}</div>
                  </div>
                  {editable ? (
                    <RoleSelect member={m} options={grantable.some((o) => o.value === formRole(m.role)) ? grantable : options} disabled={false} onChange={(r) => changeRole(m, r)} />
                  ) : (
                    <Badge tone={ownerRow ? "teal" : "neutral"}>{ROLE_LABELS[m.role] ?? m.role}</Badge>
                  )}
                  <div className="w-44 text-xs text-muted sm:text-right">{m.last_login_at ? `Last seen ${formatDateTime(m.last_login_at)}` : "Hasn't signed in yet"}</div>
                  {editable && (
                    <Button size="sm" variant="ghost" className="hover:bg-brick-soft hover:text-brick" onClick={() => setToRemove(m)}>
                      Remove
                    </Button>
                  )}
                </li>
              );
            })}
          </ul>
        )}
      </Panel>

      <Dialog
        open={adding}
        onClose={() => setAdding(false)}
        title="Add teammate"
        description="They sign in with this email and the password you set here."
        size="sm"
        footer={
          <>
            <Button onClick={() => setAdding(false)}>Cancel</Button>
            <Button variant="primary" type="submit" form="team-form" loading={saving}>
              Add teammate
            </Button>
          </>
        }
      >
        <form id="team-form" onSubmit={add} className="space-y-4" noValidate>
          <Field label="Name" htmlFor="t-name" error={errors.name}>
            <Input id="t-name" name="name" invalid={!!errors.name} autoFocus />
          </Field>
          <Field label="Email" htmlFor="t-email" error={errors.email}>
            <Input id="t-email" name="email" type="email" invalid={!!errors.email} />
          </Field>
          <Field label="Initial password" htmlFor="t-pw" error={errors.password} hint="At least 10 characters, with a letter and a number.">
            <Input id="t-pw" name="password" type="password" autoComplete="new-password" invalid={!!errors.password} />
          </Field>
          <Field label="Role" htmlFor="t-role" hint={grantable.find((o) => o.value === newRole)?.hint}>
            <Select id="t-role" name="role" value={newRole} onChange={(e) => setNewRole(e.target.value)}>
              {grantable.map((o) => (
                <option key={o.value} value={o.value}>
                  {o.label}
                </option>
              ))}
            </Select>
          </Field>
        </form>
      </Dialog>

      <ConfirmDialog
        open={!!toRemove}
        title={`Remove ${toRemove?.name}?`}
        message="They lose access to this workspace immediately, and their open chats go back to the team queue. Their account itself isn't deleted."
        confirmLabel="Remove from team"
        loading={saving}
        onConfirm={remove}
        onClose={() => setToRemove(null)}
      />
    </>
  );
}
