﻿'use client';

import { useEffect, useState } from 'react';
import { useToast } from '@/lib/hooks/useToast';
import { Check, Trash2, UserPlus, X } from 'lucide-react';
import { useAuth } from '@/lib/hooks/useAuth';
import { useOrganizationInviteLinkCopy } from '@/lib/hooks/useOrganizationInviteLinkCopy';
import {
  organizationApi,
  type CounterpartItemDto,
  type CounterpartSearchResultDto,
  type OrganizationInvitationHistoryItemDto,
} from '@/lib/api/organization';
import { invitationTargetFromConnectionRow } from '@/components/invitations/organizationInviteLinks';
import { CopyInvitationLinkButton } from '@/components/ui/organizations/CopyInvitationLinkButton';
import { InvitationHistoryDialog } from '@/components/ui/organizations/InvitationHistoryDialog';
import { Button } from '@/components/ui/common/Button';
import { Badge, organizationConnectionStatusVariant } from '@/components/ui/common/Badge';
import { Input } from '@/components/ui/common/Input';
import { SearchBar } from '@/components/ui/common/SearchBar';
import { Table } from '@/components/ui/common/Table';
import { ToastStack } from '@/components/ui/common/Toast';
import type { ApiError } from '@/types/api';

function formatOrganizationStatusLabel(status: string): string {
  if (!status) return status;
  const lower = status.toLowerCase();
  return lower.charAt(0).toUpperCase() + lower.slice(1);
}

function formatConnectionStatusLabel(
  row: CounterpartItemDto,
  currentOrganizationId: string,
): string {
  if (row.status === 'PENDING') {
    if (
      row.pendingInvitationId &&
      row.requestedByOrganizationId === currentOrganizationId
    ) {
      return 'Invitation pending';
    }
    return 'Connection request pending';
  }
  if (row.status === 'ACTIVE') return 'Connected';
  if (row.status === 'REJECTED') return 'Connection request declined';
  return formatOrganizationStatusLabel(row.status);
}

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 formatTableDate(value: string): string {
  const d = new Date(value);
  if (Number.isNaN(d.getTime())) return '\u2014';
  return d.toLocaleDateString();
}

type TableMode = 'existing' | 'search';

export default function OrganizationsPage() {
  const { currentOrganization } = useAuth();
  const [loading, setLoading] = useState(true);
  const toast = useToast();

  const [query, setQuery] = useState('');
  const [mode, setMode] = useState<TableMode>('existing');
  const [searching, setSearching] = useState(false);
  const [searchResults, setSearchResults] = useState<CounterpartSearchResultDto[]>([]);
  const [pendingConnectionRowId, setPendingConnectionRowId] = useState<string | null>(null);
  const [deleteConnectionRowId, setDeleteConnectionRowId] = useState<string | null>(null);

  const [items, setItems] = useState<CounterpartItemDto[]>([]);
  const [manualOrganizationName, setManualOrganizationName] = useState('');
  const [manualOwnerEmail, setManualOwnerEmail] = useState('');
  const [inviteLoading, setInviteLoading] = useState(false);
  const [showInviteForm, setShowInviteForm] = useState(false);
  const [historyOpen, setHistoryOpen] = useState(false);
  const [historyLoading, setHistoryLoading] = useState(false);
  const [historyItems, setHistoryItems] = useState<OrganizationInvitationHistoryItemDto[]>([]);

  const {
    copiedId,
    copyingInvitationId,
    storeInviteLink,
    copyInvitationLink,
    pruneAcceptedLinks,
  } = useOrganizationInviteLinkCopy(currentOrganization?.id);

  const counterpartLabel = currentOrganization?.type === 'LAB' ? 'Clinic' : 'Lab';
  const tabLabel = currentOrganization?.type === 'LAB' ? 'Clinics' : 'Labs';

  const existingRows = items;

  async function loadList() {
    setLoading(true);
    toast.setError('');
    try {
      const res = await organizationApi.list();
      setItems(res.data.items);
    } catch (e) {
      toast.showError(formatApiMessage(e));
    } finally {
      setLoading(false);
    }
  }

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

  async function runSearch() {
    const q = query.trim();
    if (!q) {
      setMode('existing');
      setSearchResults([]);
      setShowInviteForm(false);
      return;
    }

    setSearching(true);
    toast.setError('');
    setMode('search');
    setShowInviteForm(false);
    try {
      const res = await organizationApi.search(q);
      setSearchResults(res.data);
    } catch (e) {
      toast.showError(formatApiMessage(e));
      setSearchResults([]);
    } finally {
      setSearching(false);
    }
  }

  async function submitConnectionRequest(targetOrganizationId: string) {
    setPendingConnectionRowId(targetOrganizationId);
    toast.setError('');
    try {
      await organizationApi.createConnectionRequest(targetOrganizationId);
      toast.showSuccess(`${counterpartLabel} connection request sent.`);
      setSearchResults([]);
      setQuery('');
      setMode('existing');
      await loadList();
    } catch (e) {
      toast.showError(formatApiMessage(e));
    } finally {
      setPendingConnectionRowId(null);
    }
  }

  async function sendInvite() {
    setInviteLoading(true);
    toast.setError('');
    try {
      const res = await organizationApi.invite({
        organizationName: manualOrganizationName.trim(),
        ownerEmail: manualOwnerEmail.trim(),
      });
      storeInviteLink(res.data.invitationId, manualOwnerEmail, res.data.invitationUrl);
      toast.showSuccess(`Invitation link created for ${manualOwnerEmail.trim()}`);
      setManualOrganizationName('');
      setManualOwnerEmail('');
      setShowInviteForm(false);
      setMode('existing');
      setQuery('');
      setSearchResults([]);
      await loadList();
    } catch (e) {
      toast.showError(formatApiMessage(e));
    } finally {
      setInviteLoading(false);
    }
  }

  async function loadInvitationHistory() {
    const res = await organizationApi.listInvitations();
    setHistoryItems(res.data.items);
    pruneAcceptedLinks(res.data.items);
    return res.data.items;
  }

  async function openInvitationHistory() {
    setHistoryOpen(true);
    setHistoryLoading(true);
    toast.clear();
    try {
      await loadInvitationHistory();
    } catch (e) {
      toast.showError(formatApiMessage(e));
    } finally {
      setHistoryLoading(false);
    }
  }

  async function handleHistoryCopy(invitation: OrganizationInvitationHistoryItemDto) {
    toast.setError('');
    try {
      await copyInvitationLink(invitation, {
        onRegenerated: async () => {
          await loadInvitationHistory();
        },
      });
      toast.showSuccess('Invitation link copied to clipboard.');
    } catch (e) {
      toast.showError(formatApiMessage(e));
    }
  }

  async function handleCopyInvitationFromRow(row: CounterpartItemDto) {
    const target = invitationTargetFromConnectionRow(row, currentOrganization!.id);
    if (!target) return;
    toast.setError('');
    try {
      await copyInvitationLink(
        {
          id: target.id,
          organizationName: row.organizationName,
          ownerEmail: target.ownerEmail,
          status: target.status,
          createdAt: row.createdAt,
          acceptedAt: target.acceptedAt,
        },
        {
          onRegenerated: async () => {
            await loadList();
          },
        },
      );
      toast.showSuccess('Invitation link copied to clipboard.');
    } catch (e) {
      toast.showError(formatApiMessage(e));
    }
  }

  async function respondToPendingConnection(connectionId: string, action: 'ACCEPT' | 'REJECT') {
    setPendingConnectionRowId(connectionId);
    toast.setError('');
    try {
      await organizationApi.respondToConnectionRequest(connectionId, action);
      toast.showSuccess(
        action === 'ACCEPT' ? 'Connection request accepted.' : 'Connection request declined.',
      );
      await loadList();
    } catch (e) {
      toast.showError(formatApiMessage(e));
    } finally {
      setPendingConnectionRowId(null);
    }
  }

  async function deleteConnection(connectionId: string) {
    setDeleteConnectionRowId(connectionId);
    toast.setError('');
    try {
      await organizationApi.deleteConnection(connectionId);
      toast.showSuccess('Connection removed.');
      await loadList();
    } catch (e) {
      toast.showError(formatApiMessage(e));
    } finally {
      setDeleteConnectionRowId(null);
    }
  }

  function clearSearchView() {
    setMode('existing');
    setQuery('');
    setSearchResults([]);
    setShowInviteForm(false);
  }

  if (!currentOrganization) {
    return <p className="text-sm text-text-secondary">Loading organization...</p>;
  }

  return (
    <div className="space-y-6">
      <div className="flex flex-col gap-1 sm:flex-row sm:items-start sm:justify-between">
        <div>
          <h1 className="text-2xl font-semibold text-text-primary">{tabLabel}</h1>
          <p className="text-sm text-text-secondary mt-1">
            Search organizations, send connection requests to existing accounts, or invitation
            links when they are not on DyoLink yet.
          </p>
        </div>
        <Button type="button" size="sm" onClick={() => void openInvitationHistory()}>
          Invitation History
        </Button>
      </div>

      {!historyOpen && <ToastStack {...toast.messages} />}

      <SearchBar
        value={query}
        onChange={setQuery}
        onSubmit={() => void runSearch()}
        placeholder={`Search ${counterpartLabel.toLowerCase()} by name, email, or phone...`}
        actions={
          <>
            <button
              type="button"
              onClick={() => void runSearch()}
              disabled={searching}
              className="px-4 py-2 rounded-[var(--radius-sm)] text-sm font-medium border bg-primary-soft text-primary border-primary/50 disabled:opacity-60"
            >
              Search
            </button>
            {mode === 'search' && (
              <button
                type="button"
                onClick={clearSearchView}
                className="px-4 py-2 rounded-[var(--radius-sm)] text-sm font-medium border text-text-secondary border-border/40 hover:bg-background-card/70 hover:border-border"
              >
                Back to list
              </button>
            )}
          </>
        }
      />

      <Table
        headers={
            <tr>
              <th className="px-6 py-3 text-left text-xs font-medium text-text-muted uppercase tracking-wider">
                Organization
              </th>
              <th className="px-6 py-3 text-left text-xs font-medium text-text-muted uppercase tracking-wider">
                Owner email
              </th>
              <th className="px-6 py-3 text-left text-xs font-medium text-text-muted uppercase tracking-wider">
                Date
              </th>
              <th className="px-6 py-3 text-center text-xs font-medium text-text-muted uppercase tracking-wider">
                Status
              </th>
              <th className="px-6 py-3 text-right text-xs font-medium text-text-muted uppercase tracking-wider">
                Action
              </th>
            </tr>
        }
        body={
          <>
            {loading ? (
              <tr>
                <td colSpan={5} className="px-6 py-8 text-sm text-text-secondary">
                  Loading...
                </td>
              </tr>
            ) : mode === 'existing' ? (
              existingRows.length === 0 ? (
                <tr>
                  <td colSpan={5} className="px-6 py-8 text-sm text-text-secondary">
                    No connections yet. Search to send a connection request or an invitation link.
                  </td>
                </tr>
              ) : (
                existingRows.map((row) => {
                  const canRespond =
                    row.status === 'PENDING' &&
                    row.requestedByOrganizationId !== null &&
                    row.requestedByOrganizationId !== currentOrganization.id;
                  const invitationTarget = invitationTargetFromConnectionRow(
                    row,
                    currentOrganization.id,
                  );

                  return (
                    <tr key={row.id} className="hover:bg-background-secondary/45">
                      <td className="px-6 py-1.5 text-sm font-medium text-text-primary">
                        {row.organizationName}
                      </td>
                      <td className="px-6 py-1.5 text-sm text-text-secondary">{row.ownerEmail}</td>
                      <td className="px-6 py-1.5 text-sm text-text-secondary">
                        {formatTableDate(row.createdAt)}
                      </td>
                      <td className="px-6 py-1.5 text-center align-middle">
                        <Badge variant={organizationConnectionStatusVariant(row.status)} fixedWidth={false}>
                          {formatConnectionStatusLabel(row, currentOrganization.id)}
                        </Badge>
                      </td>
                      <td className="px-6 py-1.5 text-right">
                        <div className="inline-flex items-center gap-2">
                          {invitationTarget && (
                            <CopyInvitationLinkButton
                              invitation={invitationTarget}
                              copied={copiedId === invitationTarget.id}
                              copying={copyingInvitationId === invitationTarget.id}
                              onCopy={() => void handleCopyInvitationFromRow(row)}
                            />
                          )}
                          {canRespond && (
                            <>
                              <button
                                type="button"
                                className="p-2 rounded-md text-text-secondary hover:bg-background-card/80 hover:text-text-primary disabled:text-text-muted disabled:opacity-50"
                                disabled={pendingConnectionRowId !== null && pendingConnectionRowId !== row.id}
                                onClick={() => void respondToPendingConnection(row.id, 'ACCEPT')}
                                aria-label="Accept connection request"
                                title="Accept connection request"
                              >
                                <Check className="w-4 h-4" />
                              </button>
                              <button
                                type="button"
                                className="p-2 rounded-md text-text-secondary hover:bg-red-500/15 hover:text-red-600 disabled:text-text-muted disabled:opacity-50"
                                disabled={pendingConnectionRowId !== null && pendingConnectionRowId !== row.id}
                                onClick={() => void respondToPendingConnection(row.id, 'REJECT')}
                                aria-label="Decline connection request"
                                title="Decline connection request"
                              >
                                <X className="w-4 h-4" />
                              </button>
                            </>
                          )}
                          {row.status === 'ACTIVE' && (
                            <button
                              type="button"
                              className="p-2 rounded-md text-text-secondary hover:bg-red-500/15 hover:text-red-600 disabled:text-text-muted disabled:opacity-50"
                              disabled={deleteConnectionRowId !== null && deleteConnectionRowId !== row.id}
                              onClick={() => void deleteConnection(row.id)}
                              aria-label="Remove connection"
                              title="Remove connection"
                            >
                              <Trash2 className="w-4 h-4" />
                            </button>
                          )}
                        </div>
                      </td>
                    </tr>
                  );
                })
              )
            ) : searchResults.length > 0 ? (
              searchResults.map((r) => (
                <tr key={r.id} className="hover:bg-background-secondary/45">
                  <td className="px-6 py-1.5 text-sm font-medium text-text-primary">{r.name}</td>
                  <td className="px-6 py-1.5 text-sm text-text-secondary">{r.owner.email}</td>
                  <td className="px-6 py-1.5 text-sm text-text-secondary">Today</td>
                  <td className="px-6 py-1.5 text-center align-middle">
                    <Badge variant="default" fixedWidth={false}>Found</Badge>
                  </td>
                  <td className="px-6 py-1.5 text-right">
                    <button
                      type="button"
                      className="p-2 rounded-md text-text-secondary hover:bg-background-card/80 hover:text-text-primary disabled:text-text-muted disabled:opacity-50"
                      disabled={
                        pendingConnectionRowId !== null && pendingConnectionRowId !== r.id
                      }
                      onClick={() => void submitConnectionRequest(r.id)}
                      aria-label="Send connection request"
                      title="Send connection request"
                    >
                      <UserPlus className="w-4 h-4" />
                    </button>
                  </td>
                </tr>
              ))
            ) : (
              <tr>
                <td colSpan={5} className="px-6 py-6">
                  <div className="flex flex-col gap-3">
                    <p className="text-sm text-text-secondary">
                      No organization found in directory search.
                    </p>
                    <div className="flex flex-wrap items-center gap-2">
                      <Button type="button" onClick={() => setShowInviteForm((v) => !v)}>
                        {showInviteForm ? 'Hide invitation fields' : 'Send invitation link'}
                      </Button>
                    </div>
                    {showInviteForm && (
                      <div className="grid gap-3 sm:grid-cols-3 mt-1">
                        <Input
                          label={`${counterpartLabel} name`}
                          value={manualOrganizationName}
                          onChange={(e) => setManualOrganizationName(e.target.value)}
                        />
                        <Input
                          label="Owner email"
                          type="email"
                          value={manualOwnerEmail}
                          onChange={(e) => setManualOwnerEmail(e.target.value)}
                        />
                        <div className="flex items-end">
                          <Button
                            type="button"
                            isLoading={inviteLoading}
                            disabled={!manualOrganizationName.trim() || !manualOwnerEmail.trim()}
                            onClick={() => void sendInvite()}
                            className="w-full"
                          >
                            Send invitation
                          </Button>
                        </div>
                      </div>
                    )}
                  </div>
                </td>
              </tr>
            )}
          </>
        }
      />

      <InvitationHistoryDialog
        open={historyOpen}
        onClose={() => setHistoryOpen(false)}
        loading={historyLoading}
        items={historyItems}
        copiedId={copiedId}
        copyingInvitationId={copyingInvitationId}
        onCopy={(invitation) => void handleHistoryCopy(invitation)}
        toastMessages={toast.messages}
      />
    </div>
  );
}
