'use client';

import { useCallback, useEffect, useMemo, useState } from 'react';
import { useRouter } from 'next/navigation';
import {
  firstAccessibleDashboardPath,
  canEditStaff,
  canViewStaff,
} from '@/shared/permissions';
import {
  STAFF_FEATURE_GROUPS,
  permissionNamesFromFeatureState,
  emptyFeaturePermissionState,
  featureStateFromPermissionNames,
  resolveStaffFeatureLabel,
  formatAccessSummary,
  type FeaturePermState,
} from './staff-permission-form';
import { Pencil, Trash2, Copy, Check, X } from 'lucide-react';
import { useAuth } from '@/lib/hooks/useAuth';
import { staffApi, type StaffMemberDto } from '@/lib/api/staff';
import { Button } from '@/components/ui/common/Button';
import { Badge } from '@/components/ui/common/Badge';
import { Input } from '@/components/ui/common/Input';
import { Checkbox } from '@/components/ui/common/Checkbox';
import type { ApiError } from '@/types/api';

type StoredInviteLink = {
  membershipId: string;
  email: string;
  invitationUrl: string;
};

function inviteLinksStorageKey(orgId: string): string {
  return `staffInviteLinks:${orgId}`;
}

function readStoredInviteLinks(orgId: string): Record<string, StoredInviteLink> {
  if (typeof window === 'undefined') return {};
  try {
    const raw = window.localStorage.getItem(inviteLinksStorageKey(orgId));
    if (!raw) return {};
    const parsed = JSON.parse(raw) as Record<string, StoredInviteLink>;
    return parsed && typeof parsed === 'object' ? parsed : {};
  } catch {
    return {};
  }
}

function writeStoredInviteLinks(orgId: string, links: Record<string, StoredInviteLink>) {
  if (typeof window === 'undefined') return;
  window.localStorage.setItem(inviteLinksStorageKey(orgId), JSON.stringify(links));
}

function formatApiMessage(err: unknown): string {
  if (!err || typeof err !== 'object') return 'Something went wrong';
  const m = (err as ApiError).message;
  if (Array.isArray(m)) return m.join(', ');
  if (typeof m === 'string') return m;
  return 'Something went wrong';
}

function PermissionGrid({
  state,
  onChange,
  disabled,
  organizationType,
}: {
  state: FeaturePermState;
  onChange: (next: FeaturePermState) => void;
  disabled?: boolean;
  organizationType?: 'CLINIC' | 'LAB';
}) {
  const setRead = (editKey: string, read: boolean) => {
    const cur = state[editKey] ?? { read: false, edit: false };
    onChange({
      ...state,
      [editKey]: { read, edit: read ? cur.edit : false },
    });
  };

  const setEdit = (editKey: string, edit: boolean) => {
    const cur = state[editKey] ?? { read: false, edit: false };
    onChange({
      ...state,
      [editKey]: { read: edit || cur.read, edit },
    });
  };

  return (
    <div className="grid gap-3 sm:grid-cols-2">
      {STAFF_FEATURE_GROUPS.map((g) => {
        const cell = state[g.edit] ?? { read: false, edit: false };
        return (
          <div
            key={g.edit}
            className="flex flex-col gap-3 rounded-[var(--radius-md)] border border-border/60 bg-background-card/50 px-3 py-3"
          >
            <span className="text-sm font-medium text-text-primary">
              {resolveStaffFeatureLabel(g, organizationType)}
            </span>
            <div className="flex flex-col gap-2.5 pl-0.5">
              <Checkbox
                checked={cell.read}
                disabled={disabled}
                label="View"
                onChange={(v) => setRead(g.edit, v)}
              />
              <Checkbox
                checked={cell.edit}
                disabled={disabled}
                label="Edit"
                onChange={(v) => setEdit(g.edit, v)}
              />
            </div>
          </div>
        );
      })}
    </div>
  );
}

export default function StaffPage() {
  const router = useRouter();
  const { currentOrganization, user } = useAuth();
  const [members, setMembers] = useState<StaffMemberDto[]>([]);
  const [seats, setSeats] = useState<{
    used: number;
    limit: number | null;
    unlimited: boolean;
  } | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [success, setSuccess] = useState('');

  const [inviteOpen, setInviteOpen] = useState(false);
  const [inviteEmail, setInviteEmail] = useState('');
  const [inviteName, setInviteName] = useState('');
  const [invitePerms, setInvitePerms] = useState(() => emptyFeaturePermissionState());
  const [inviteLoading, setInviteLoading] = useState(false);
  const [copiedInviteMembershipId, setCopiedInviteMembershipId] = useState<string | null>(null);
  const [lastInviteInfo, setLastInviteInfo] = useState<{
    membershipId: string;
    name: string;
    email: string;
    invitationUrl: string | null;
    invitationStatus: 'PENDING' | 'ACCEPTED';
  } | null>(null);
  const [pendingInviteLinks, setPendingInviteLinks] = useState<Record<string, StoredInviteLink>>({});

  const [editing, setEditing] = useState<StaffMemberDto | null>(null);
  const [editName, setEditName] = useState('');
  const [editPerms, setEditPerms] = useState(() => emptyFeaturePermissionState());
  const [editLoading, setEditLoading] = useState(false);

  const canEdit = useMemo(() => canEditStaff(currentOrganization), [currentOrganization]);
  const hasActivePlan = Boolean(currentOrganization?.plan);
  const atSeatLimit = useMemo(() => {
    if (!seats || seats.unlimited) return false;
    if (seats.limit == null) return false;
    return seats.used >= seats.limit;
  }, [seats]);

  const load = useCallback(async () => {
    setError('');
    setLoading(true);
    try {
      const res = await staffApi.list();
      setMembers(res.data.members);
      setSeats(res.data.seats);
    } catch (e) {
      setError(formatApiMessage(e));
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    if (!currentOrganization?.id) return;
    setPendingInviteLinks(readStoredInviteLinks(currentOrganization.id));
  }, [currentOrganization?.id]);

  useEffect(() => {
    if (!currentOrganization?.id || loading) return;

    const activeMemberIds = new Set(
      members
        .filter((m) => m.isOwner || m.invitationStatus === 'ACTIVE')
        .map((m) => m.id),
    );

    let changed = false;
    const nextLinks: Record<string, StoredInviteLink> = { ...pendingInviteLinks };
    for (const memberId of Object.keys(nextLinks)) {
      if (activeMemberIds.has(memberId)) {
        delete nextLinks[memberId];
        changed = true;
      }
    }
    if (!changed) return;

    setPendingInviteLinks(nextLinks);
    writeStoredInviteLinks(currentOrganization.id, nextLinks);
  }, [currentOrganization?.id, loading, members, pendingInviteLinks]);

  useEffect(() => {
    void load();
  }, [load]);

  useEffect(() => {
    if (!currentOrganization) return;
    if (!canViewStaff(currentOrganization)) {
      router.replace(firstAccessibleDashboardPath(currentOrganization));
    }
  }, [currentOrganization, router]);

  useEffect(() => {
    if (!success) return;
    const t = setTimeout(() => setSuccess(''), 4000);
    return () => clearTimeout(t);
  }, [success]);

  async function submitInvite() {
    setInviteLoading(true);
    setError('');
    setLastInviteInfo(null);
    const displayName = inviteName.trim();
    const displayEmail = inviteEmail.trim();
    try {
      const permissionNames = permissionNamesFromFeatureState(invitePerms);
      const res = await staffApi.invite({
        email: displayEmail,
        name: displayName,
        permissionNames,
      });
      setLastInviteInfo({
        membershipId: res.data.membershipId,
        name: displayName,
        email: res.data.email,
        invitationUrl: res.data.invitationUrl,
        invitationStatus: res.data.invitationStatus,
      });
      if (currentOrganization?.id && res.data.invitationUrl) {
        const nextLinks = {
          ...pendingInviteLinks,
          [res.data.membershipId]: {
            membershipId: res.data.membershipId,
            email: res.data.email,
            invitationUrl: res.data.invitationUrl,
          },
        };
        setPendingInviteLinks(nextLinks);
        writeStoredInviteLinks(currentOrganization.id, nextLinks);
      }
      setSuccess('');
      setInviteOpen(false);
      setInviteEmail('');
      setInviteName('');
      setInvitePerms(emptyFeaturePermissionState());
      await load();
    } catch (e) {
      setError(formatApiMessage(e));
    } finally {
      setInviteLoading(false);
    }
  }

  function openEdit(m: StaffMemberDto) {
    if (m.isOwner) return;
    setEditing(m);
    setEditName(m.name);
    setEditPerms(
      featureStateFromPermissionNames(m.permissions ?? []),
    );
  }

  async function submitEdit() {
    if (!editing) return;
    setEditLoading(true);
    setError('');
    try {
      await staffApi.updateMember(editing.id, {
        name: editName.trim(),
        permissionNames: permissionNamesFromFeatureState(editPerms),
      });
      setSuccess('Member updated');
      setEditing(null);
      await load();
    } catch (e) {
      setError(formatApiMessage(e));
    } finally {
      setEditLoading(false);
    }
  }

  async function removeMember(m: StaffMemberDto) {
    if (m.isOwner) return;
    if (m.userId === user?.id) {
      if (!confirm('Remove yourself from this organization? You will lose access.')) return;
    } else {
      if (!confirm(`Remove ${m.name} from this organization?`)) return;
    }
    setError('');
    try {
      await staffApi.removeMember(m.id);
      setSuccess('Member removed');
      await load();
    } catch (e) {
      setError(formatApiMessage(e));
    }
  }

  if (!currentOrganization || !canViewStaff(currentOrganization)) {
    return (
      <p className="text-sm text-text-secondary">Redirecting…</p>
    );
  }

  return (
    <div className="space-y-6">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
        <div>
          <h1 className="text-2xl font-semibold text-text-primary">Staff Management</h1>
          <p className="text-sm text-text-secondary mt-1">
            Invite teammates, set tab access, and stay within your plan seat limit.
          </p>
        </div>
        <Button
          size="sm"
          onClick={() => {
            if (!canEdit || atSeatLimit) return;
            setInviteOpen(true);
            setLastInviteInfo(null);
          }}
          disabled={!canEdit || atSeatLimit}
          className="shrink-0"
          title={!canEdit ? 'Read-only access for this organization.' : undefined}
        >
          Invite member
        </Button>
      </div>

      {seats && (
        <p className="text-sm text-text-secondary">
          Seats:{' '}
          <span className="text-text-primary font-medium">
            {seats.used}
            {seats.unlimited ? ' (unlimited plan)' : ` / ${seats.limit}`}
          </span>
          {!seats.unlimited && atSeatLimit && (
            <span className="text-amber-600 dark:text-amber-400 ml-2">
              {hasActivePlan
                ? 'Plan seat limit reached for this organization.'
                : 'No active plan selected for this organization. Choose a subscription plan to invite members.'}
            </span>
          )}
        </p>
      )}

      {error && (
        <div className="rounded-[var(--radius-md)] border border-red-500/40 bg-red-500/10 px-4 py-3 text-sm text-red-700 dark:text-red-300">
          {error}
        </div>
      )}

      {success && (
        <div className="rounded-[var(--radius-md)] border border-primary/30 bg-primary-soft/40 px-4 py-3 text-sm text-text-primary">
          {success}
        </div>
      )}

      {lastInviteInfo && (
        <div className="relative rounded-[var(--radius-md)] border border-border-strong bg-background-secondary/90 px-4 py-3 pr-12 shadow-[inset_0_1px_0_rgba(255,255,255,0.04)] space-y-3">
          <button
            type="button"
            className="absolute right-2 top-2 p-1.5 rounded-[var(--radius-sm)] text-text-muted hover:text-text-primary hover:bg-background-card/80"
            aria-label="Dismiss"
            onClick={() => {
              setLastInviteInfo(null);
            }}
          >
            <X className="w-4 h-4" />
          </button>
          <p className="text-sm text-text-primary pr-6">
            <span className="font-medium">{lastInviteInfo.name}</span> ({lastInviteInfo.email}) was invited.
            {lastInviteInfo.invitationStatus === 'PENDING'
              ? ' Invitation is pending until they open the link, set a password, and log in.'
              : ' Invitation was accepted immediately.'}
          </p>
          {lastInviteInfo.invitationUrl && (
            <div className="space-y-2 pt-1 border-t border-border/60">
              <p className="text-xs font-medium text-text-secondary uppercase tracking-wide">
                Invite link
              </p>
              <div className="flex flex-wrap items-center gap-2">
                <code className="text-sm px-2 py-1.5 rounded-[var(--radius-sm)] bg-background-card border border-border font-mono break-all">
                  {lastInviteInfo.invitationUrl}
                </code>
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={async () => {
                    try {
                      await navigator.clipboard.writeText(lastInviteInfo.invitationUrl as string);
                      setCopiedInviteMembershipId(lastInviteInfo.membershipId);
                      setTimeout(() => setCopiedInviteMembershipId(null), 1500);
                    } catch {
                      setError('Could not copy invitation link');
                    }
                  }}
                >
                  {copiedInviteMembershipId === lastInviteInfo.membershipId ? 'Copied' : 'Copy link'}
                </Button>
              </div>
              <p className="text-xs text-text-muted">
                Share this link manually via SMS or email. They must set password first.
              </p>
            </div>
          )}
        </div>
      )}

      {loading ? (
        <p className="text-sm text-text-secondary">Loading team…</p>
      ) : (
        <div className="overflow-x-auto rounded-[var(--radius-md)] border border-border/70">
          <table className="w-full text-sm">
            <thead>
              <tr className="border-b border-border/70 text-left text-text-secondary">
                <th className="p-3 font-medium">Name</th>
                <th className="p-3 font-medium">Email</th>
                <th className="p-3 font-medium">Role</th>
                <th className="p-3 font-medium text-center">Status</th>
                <th className="p-3 font-medium">Access</th>
                <th className="p-3 font-medium w-28">Actions</th>
              </tr>
            </thead>
            <tbody>
              {members.map((m) => (
                <tr key={m.id} className="h-14 border-b border-border/40 last:border-0">
                  <td className="p-3 text-text-primary">{m.name}</td>
                  <td className="p-3 text-text-secondary">{m.email}</td>
                  <td className="p-3">
                    {m.isOwner ? (
                      <span className="text-primary font-medium">Owner</span>
                    ) : (
                      <span className="text-text-secondary">Staff</span>
                    )}
                  </td>
                  <td className="p-3 align-middle text-center">
                    {m.isOwner || m.invitationStatus === 'ACTIVE' ? (
                      <Badge variant="success">Active</Badge>
                    ) : m.invitationStatus === 'PENDING' ? (
                      <Badge variant="warning">Pending</Badge>
                    ) : (
                      <Badge variant="danger">Expired</Badge>
                    )}
                  </td>
                  <td className="p-3 text-text-secondary max-w-md">
                    {m.isOwner ? (
                      <span className="text-text-muted">All features</span>
                    ) : (
                      <span className="line-clamp-3 text-sm leading-relaxed">
                        {formatAccessSummary(m.permissions, currentOrganization?.type)}
                      </span>
                    )}
                  </td>
                  <td className="p-3 align-middle">
                    {!m.isOwner && (
                      <div className="flex min-h-[36px] items-center justify-end gap-1">
                        {m.invitationStatus === 'PENDING' && pendingInviteLinks[m.id]?.invitationUrl && (
                          <button
                            type="button"
                            className="p-2 rounded-md text-text-secondary hover:bg-background-card/80 hover:text-text-primary"
                            onClick={async () => {
                              try {
                                await navigator.clipboard.writeText(pendingInviteLinks[m.id].invitationUrl);
                                setCopiedInviteMembershipId(m.id);
                                setTimeout(() => setCopiedInviteMembershipId(null), 1500);
                              } catch {
                                setError('Could not copy invitation link');
                              }
                            }}
                            aria-label="Copy invite link"
                            title="Copy invite link"
                          >
                            {copiedInviteMembershipId === m.id ? (
                              <Check className="w-4 h-4" />
                            ) : (
                              <Copy className="w-4 h-4" />
                            )}
                          </button>
                        )}
                        <button
                          type="button"
                          className={`p-2 rounded-md ${
                            canEdit
                              ? 'text-text-secondary hover:bg-background-card/80 hover:text-text-primary'
                              : 'text-text-muted opacity-50 cursor-not-allowed'
                          }`}
                          aria-label="Edit member"
                          disabled={!canEdit}
                          onClick={() => {
                            if (!canEdit) return;
                            openEdit(m);
                          }}
                        >
                          <Pencil className="w-4 h-4" />
                        </button>
                        <button
                          type="button"
                          className={`p-2 rounded-md ${
                            canEdit
                              ? 'text-text-secondary hover:bg-red-500/15 hover:text-red-600'
                              : 'text-text-muted opacity-50 cursor-not-allowed'
                          }`}
                          aria-label="Remove member"
                          disabled={!canEdit}
                          onClick={() => {
                            if (!canEdit) return;
                            void removeMember(m);
                          }}
                        >
                          <Trash2 className="w-4 h-4" />
                        </button>
                      </div>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {inviteOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50">
          <div
            className="w-full max-w-lg max-h-[90vh] overflow-y-auto rounded-[var(--radius-md)] border border-border bg-background-secondary p-6 shadow-xl space-y-4"
            role="dialog"
            aria-modal="true"
            aria-labelledby="invite-staff-title"
          >
            <h2 id="invite-staff-title" className="text-lg font-semibold text-text-primary">
              Invite team member
            </h2>
            <Input
              label="Email"
              type="email"
              value={inviteEmail}
              onChange={(e) => setInviteEmail(e.target.value)}
              autoComplete="off"
            />
            <Input
              label="Display name"
              value={inviteName}
              onChange={(e) => setInviteName(e.target.value)}
            />
            <div>
              <p className="text-sm font-medium text-text-secondary mb-2">Tab access</p>
              <PermissionGrid
                state={invitePerms}
                onChange={setInvitePerms}
                organizationType={currentOrganization?.type}
              />
            </div>
            <div className="flex justify-end gap-2 pt-2">
              <Button variant="outline" type="button" onClick={() => setInviteOpen(false)}>
                Cancel
              </Button>
              <Button
                type="button"
                isLoading={inviteLoading}
                disabled={!inviteEmail.trim() || !inviteName.trim()}
                onClick={() => void submitInvite()}
              >
                Send invite
              </Button>
            </div>
          </div>
        </div>
      )}

      {editing && (
        <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50">
          <div
            className="w-full max-w-lg max-h-[90vh] overflow-y-auto rounded-[var(--radius-md)] border border-border bg-background-secondary p-6 shadow-xl space-y-4"
            role="dialog"
            aria-modal="true"
          >
            <h2 className="text-lg font-semibold text-text-primary">Edit member</h2>
            <p className="text-xs text-text-muted">{editing.email}</p>
            <Input label="Display name" value={editName} onChange={(e) => setEditName(e.target.value)} />
            <div>
              <p className="text-sm font-medium text-text-secondary mb-2">Tab access</p>
              <PermissionGrid
                state={editPerms}
                onChange={setEditPerms}
                organizationType={currentOrganization?.type}
              />
            </div>
            <div className="flex justify-end gap-2 pt-2">
              <Button variant="outline" type="button" onClick={() => setEditing(null)}>
                Cancel
              </Button>
              <Button type="button" isLoading={editLoading} onClick={() => void submitEdit()}>
                Save
              </Button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
