import { useState } from 'react';
import { Users, Plus, Pencil, Trash2, Check, X, Loader2 } from 'lucide-react';
import type { OffscaleUserWithCounts } from './shared';
import { useOffscaleUsers } from './useOffscaleData';
import { offscaleErrorMessage } from './useOffscaleServers';
import { timeAgo } from './format';
import { Card, Button, Field, Badge, ErrorNote, Dot } from './Cards';
import { ViewShell, EmptyBody } from './ViewShell';

// The users section. A Headscale user is a namespace that owns nodes and pre-auth keys — not a login.
//
// The node count next to each user is the point of this screen: Headscale refuses to delete a user that
// still owns nodes, and without the count that refusal arrives as a surprise after the confirm click.

type UserRowProps = { user: OffscaleUserWithCounts; onError: (message: string) => void };

const UserRow = ({ user, onError }: UserRowProps) => {
  const { rename, remove } = useOffscaleUsers();
  const [renaming, setRenaming] = useState(false);
  const [draft, setDraft] = useState(user.name);
  const [confirming, setConfirming] = useState(false);

  const busy = rename.isPending || remove.isPending;

  const run = async (fn: () => Promise<unknown>) => {
    try {
      await fn();
    } catch (err) {
      onError(offscaleErrorMessage(err));
    }
  };

  const submitRename = async () => {
    const name = draft.trim();
    setRenaming(false);
    if (!name || name === user.name) return;
    await run(() => rename.mutateAsync({ id: user.id, name }));
  };

  return (
    <Card>
      <div className="flex flex-wrap items-center gap-3 p-3.5">
        <Dot tone={user.onlineCount > 0 ? 'ok' : 'idle'} />
        <div className="min-w-0 flex-1">
          {renaming ? (
            <div className="flex items-center gap-1.5">
              <input
                value={draft}
                onChange={(ev) => setDraft(ev.target.value)}
                onKeyDown={(ev) => {
                  if (ev.key === 'Enter') void submitRename();
                  if (ev.key === 'Escape') setRenaming(false);
                }}
                autoFocus
                spellCheck={false}
                className="min-w-0 flex-1 rounded-md border border-white/10 bg-black/40 px-2 py-1 text-sm text-zinc-100 outline-none focus:border-primary/50"
              />
              <button type="button" onClick={() => void submitRename()} className="cursor-pointer p-1 text-emerald-400">
                <Check className="h-3.5 w-3.5" />
              </button>
              <button type="button" onClick={() => setRenaming(false)} className="cursor-pointer p-1 text-zinc-500">
                <X className="h-3.5 w-3.5" />
              </button>
            </div>
          ) : (
            <div className="flex flex-wrap items-center gap-2">
              <span className="truncate text-sm font-medium text-zinc-100">{user.name}</span>
              {user.provider && <Badge>{user.provider}</Badge>}
            </div>
          )}
          <div className="mt-0.5 flex flex-wrap items-center gap-x-2 text-[11px] text-zinc-500">
            <span>
              {user.nodeCount} node{user.nodeCount === 1 ? '' : 's'}
              {user.onlineCount > 0 && `, ${user.onlineCount} online`}
            </span>
            {user.email && <span>· {user.email}</span>}
            <span>· created {timeAgo(user.createdAt)}</span>
          </div>
        </div>

        <div className="flex shrink-0 flex-wrap items-center gap-2">
          <Button
            onClick={() => {
              setDraft(user.name);
              setRenaming(true);
            }}
            disabled={busy}
          >
            <Pencil className="h-3.5 w-3.5" />
            Rename
          </Button>
          {confirming ? (
            <>
              <Button variant="danger" onClick={() => void run(() => remove.mutateAsync(user.id))} disabled={busy}>
                <Trash2 className="h-3.5 w-3.5" />
                {user.nodeCount > 0 ? `Delete with ${user.nodeCount} node(s)` : 'Confirm delete'}
              </Button>
              <Button onClick={() => setConfirming(false)} disabled={busy}>
                Cancel
              </Button>
            </>
          ) : (
            <Button variant="danger" onClick={() => setConfirming(true)} disabled={busy}>
              <Trash2 className="h-3.5 w-3.5" />
              Delete
            </Button>
          )}
        </div>
      </div>
    </Card>
  );
};

const CreateUserForm = ({ onClose }: { onClose: () => void }) => {
  const { create } = useOffscaleUsers();
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [error, setError] = useState<string | null>(null);

  const submit = async () => {
    setError(null);
    if (!name.trim()) return setError('A name is required');
    try {
      await create.mutateAsync({ name: name.trim(), email: email.trim() || undefined });
      onClose();
    } catch (err) {
      setError(offscaleErrorMessage(err));
    }
  };

  return (
    <Card>
      <form
        onSubmit={(ev) => {
          ev.preventDefault();
          void submit();
        }}
        className="flex flex-col gap-3 p-4"
      >
        <div className="text-sm font-semibold text-zinc-100">New user</div>
        <Field
          label="Name"
          value={name}
          onChange={setName}
          placeholder="laptop-fleet"
          hint="Lowercase, no spaces. This is the namespace nodes and keys belong to."
          autoFocus
        />
        <Field label="Email (optional)" value={email} onChange={setEmail} placeholder="someone@example.com" />
        {error && <ErrorNote>{error}</ErrorNote>}
        <div className="flex items-center gap-2 pt-1">
          <Button type="submit" variant="primary" disabled={create.isPending}>
            {create.isPending && <Loader2 className="h-3.5 w-3.5 animate-spin" />}
            Create user
          </Button>
          <Button onClick={onClose} disabled={create.isPending}>
            Cancel
          </Button>
        </div>
      </form>
    </Card>
  );
};

export const UsersView = () => {
  const { users, isLoading, error } = useOffscaleUsers();
  const [creating, setCreating] = useState(false);
  const [actionError, setActionError] = useState<string | null>(null);

  return (
    <ViewShell isLoading={isLoading} error={error} label="users">
      <div className="mx-auto flex w-full max-w-2xl flex-col gap-3">
        <div className="flex items-start justify-between gap-4 px-1 pb-1">
          <div className="min-w-0">
            <h2 className="text-sm font-semibold text-zinc-100">Users</h2>
            <p className="mt-0.5 text-xs text-zinc-500">Namespaces that own nodes and pre-auth keys.</p>
          </div>
          {!creating && (
            <Button variant="primary" onClick={() => setCreating(true)}>
              <Plus className="h-3.5 w-3.5" />
              New user
            </Button>
          )}
        </div>

        {creating && <CreateUserForm onClose={() => setCreating(false)} />}
        {actionError && <ErrorNote>{actionError}</ErrorNote>}

        {users.length === 0 && !creating && (
          <EmptyBody
            icon={<Users className="h-6 w-6" />}
            title="No users yet"
            hint="Every node belongs to a user. Create one before issuing a pre-auth key."
          />
        )}

        {users.map((user) => (
          <UserRow key={user.id} user={user} onError={setActionError} />
        ))}
      </div>
    </ViewShell>
  );
};
