'use client';

import { useCallback, useEffect, useState } from 'react';
import { useSearchParams } from 'next/navigation';
import { useLocale, useTranslations } from 'next-intl';
import { useToast } from '@/lib/hooks/useToast';
import { useAsyncActionById } from '@/lib/hooks/useAsyncAction';
import { Check, Trash2, UserPlus, X } from 'lucide-react';
import { useAuth } from '@/lib/hooks/useAuth';
import { notifyPendingConnectionsChanged } from '@/lib/hooks/usePendingConnectionsCount';
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 { OrganizationConnectionsMobileList } from '@/components/ui/organizations/OrganizationConnectionsMobileList';
import { InvitationHistoryDialog } from '@/components/ui/organizations/InvitationHistoryDialog';
import { Button } from '@/components/ui/shared/Button';
import { Badge } from '@/components/ui/shared/Badge';
import { organizationConnectionStatusVariant } from '@/components/organizations/connectionStatusVariant';
import { Input } from '@/components/ui/shared/Input';
import { SearchBar } from '@/components/ui/shared/SearchBar';
import { Table } from '@/components/ui/shared/Table';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { useRouter } from '@/i18n/navigation';
import { formatAppTableDate } from '@/lib/i18n/format';

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

type TableMode = 'existing' | 'search';

export function OrganizationsPage() {
  const locale = useLocale();
  const t = useTranslations('organizations');
  const tErrors = useTranslations('errors');
  const tNav = useTranslations('nav');
  const tCommon = useTranslations('common');
  const searchParams = useSearchParams();
  const router = useRouter();
  const { currentOrganization } = useAuth();
  const [loading, setLoading] = useState(true);
  const toast = useToast();
  const { showError, setError: setToastError } = toast;

  const formatApiMessage = useCallback(
    (err: unknown): string => getUserFacingError(err, tErrors, tCommon('errorGeneric')),
    [tCommon, tErrors],
  );

  const formatTableDate = useCallback(
    (value: string) => formatAppTableDate(value, locale),
    [locale],
  );

  const formatConnectionStatusLabel = useCallback(
    (row: CounterpartItemDto, currentOrganizationId: string): string => {
      if (row.status === 'PENDING') {
        if (
          row.pendingInvitationId &&
          row.requestedByOrganizationId === currentOrganizationId
        ) {
          return t('statusInvitationPending');
        }
        return t('statusConnectionPending');
      }
      if (row.status === 'ACTIVE') return t('statusConnected');
      if (row.status === 'REJECTED') return t('statusDeclined');
      return formatOrganizationStatusLabel(row.status);
    },
    [t],
  );

  const [query, setQuery] = useState('');
  const [mode, setMode] = useState<TableMode>('existing');
  const [searching, setSearching] = useState(false);
  const [searchResults, setSearchResults] = useState<CounterpartSearchResultDto[]>([]);
  const connectionBusy = useAsyncActionById();
  const deleteBusy = useAsyncActionById();

  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 counterpart =
    currentOrganization?.type === 'LAB' ? t('counterpartClinic') : t('counterpartLab');
  const tabLabel = currentOrganization?.type === 'LAB' ? tNav('clinics') : tNav('labs');

  const existingRows = items;

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

  useEffect(() => {
    void loadList();
    // eslint-disable-next-line react-hooks/exhaustive-deps -- mount-only
  }, []);

  useEffect(() => {
    const onChanged = () => {
      void loadList({ silent: true });
    };
    window.addEventListener('pending-connections-changed', onChanged);
    return () => window.removeEventListener('pending-connections-changed', onChanged);
    // eslint-disable-next-line react-hooks/exhaustive-deps -- soft refresh from live inbox
  }, []);

  useEffect(() => {
    if (searchParams.get('action') !== 'invite-lab') {
      return;
    }
    setShowInviteForm(true);
    router.replace('/organizations');
  }, [searchParams, router]);

  useEffect(() => {
    let cancelled = false;
    const q = query.trim();

    if (!q) {
      setMode('existing');
      setSearchResults([]);
      setShowInviteForm(false);
      setSearching(false);
      return;
    }

    setMode('search');
    setShowInviteForm(false);
    setSearching(true);

    const timeout = setTimeout(() => {
      void (async () => {
        setToastError('');
        try {
          const res = await organizationApi.search(q);
          if (cancelled) return;
          setSearchResults(res.data);
        } catch (e) {
          if (cancelled) return;
          showError(formatApiMessage(e));
          setSearchResults([]);
        } finally {
          if (!cancelled) setSearching(false);
        }
      })();
    }, 300);

    return () => {
      cancelled = true;
      clearTimeout(timeout);
    };
  }, [query, formatApiMessage, showError, setToastError]);

  async function submitConnectionRequest(targetOrganizationId: string) {
    await connectionBusy.run(targetOrganizationId, async () => {
      toast.setError('');
      try {
        await organizationApi.createConnectionRequest(targetOrganizationId);
        toast.showSuccess(t('successConnectionSent', { counterpart }));
        setSearchResults([]);
        setQuery('');
        setMode('existing');
        await loadList();
      } catch (e) {
        toast.showError(formatApiMessage(e));
      }
    });
  }

  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(t('successInviteCreated', { email: 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(t('successLinkCopied'));
    } 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(t('successLinkCopied'));
    } catch (e) {
      toast.showError(formatApiMessage(e));
    }
  }

  async function respondToPendingConnection(connectionId: string, action: 'ACCEPT' | 'REJECT') {
    await connectionBusy.run(connectionId, async () => {
      toast.setError('');
      try {
        await organizationApi.respondToConnectionRequest(connectionId, action);
        toast.showSuccess(
          action === 'ACCEPT' ? t('successAccepted') : t('successDeclined'),
        );
        notifyPendingConnectionsChanged();
        await loadList();
      } catch (e) {
        toast.showError(formatApiMessage(e));
      }
    });
  }

  async function deleteConnection(connectionId: string) {
    await deleteBusy.run(connectionId, async () => {
      toast.setError('');
      try {
        await organizationApi.deleteConnection(connectionId);
        toast.showSuccess(t('successRemoved'));
        await loadList();
      } catch (e) {
        toast.showError(formatApiMessage(e));
      }
    });
  }

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

  if (!currentOrganization) {
    return <p className="text-sm text-text-secondary">{t('loadingOrganization')}</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-xl sm:text-2xl font-semibold text-text-primary">{tabLabel}</h1>
          <p className="text-sm text-text-secondary mt-1">{t('subtitle')}</p>
        </div>
        <Button type="button" size="sm" className="w-full sm:w-auto shrink-0" onClick={() => openInvitationHistory()}>
          {t('invitationHistory')}
        </Button>
      </div>

      <SearchBar
        value={query}
        onChange={setQuery}
        placeholder={t('searchPlaceholder', { counterpart: counterpart.toLowerCase() })}
        actions={
          query.trim() ? (
            <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"
            >
              {t('backToList')}
            </button>
          ) : undefined
        }
      />

      <OrganizationConnectionsMobileList
        loading={loading || searching}
        mode={mode}
        existingRows={existingRows}
        searchResults={searchResults}
        currentOrganizationId={currentOrganization.id}
        counterpart={counterpart}
        pendingConnectionRowId={connectionBusy.pendingId}
        deleteConnectionRowId={deleteBusy.pendingId}
        copiedId={copiedId}
        copyingInvitationId={copyingInvitationId}
        showInviteForm={showInviteForm}
        manualOrganizationName={manualOrganizationName}
        manualOwnerEmail={manualOwnerEmail}
        inviteLoading={inviteLoading}
        formatConnectionStatusLabel={formatConnectionStatusLabel}
        formatTableDate={formatTableDate}
        getInvitationTarget={(row) => invitationTargetFromConnectionRow(row, currentOrganization.id)}
        onCopyInvitation={(row) => handleCopyInvitationFromRow(row)}
        onRespond={(rowId, action) => respondToPendingConnection(rowId, action)}
        onDeleteConnection={(rowId) => deleteConnection(rowId)}
        onSendConnectionRequest={(orgId) => submitConnectionRequest(orgId)}
        onToggleInviteForm={() => setShowInviteForm((v) => !v)}
        onManualOrganizationNameChange={setManualOrganizationName}
        onManualOwnerEmailChange={setManualOwnerEmail}
        onSendInvite={() => sendInvite()}
        labels={{
          loading: tCommon('loadingEllipsis'),
          emptyConnections: t('emptyConnections'),
          noDirectoryResults: t('noDirectoryResults'),
          hideInvitationFields: t('hideInvitationFields'),
          sendInvitationLink: t('sendInvitationLink'),
          counterpartNameLabel: t('counterpartNameLabel', { counterpart }),
          ownerEmailLabel: t('ownerEmailLabel'),
          sendInvitation: t('sendInvitation'),
          sendRequest: t('sendRequest'),
          acceptRequest: t('acceptRequest'),
          declineRequest: t('declineRequest'),
          removeConnection: t('removeConnection'),
          statusToday: t('statusToday'),
          statusFound: t('statusFound'),
        }}
      />

      <div className="hidden lg:block">
      <Table
        headers={
            <tr>
              <th className="text-xs font-medium text-text-muted uppercase tracking-wider">
                {t('tableOrganization')}
              </th>
              <th className="text-xs font-medium text-text-muted uppercase tracking-wider">
                {t('tableOwnerEmail')}
              </th>
              <th className="text-xs font-medium text-text-muted uppercase tracking-wider">
                {t('tableDate')}
              </th>
              <th className="text-center text-xs font-medium text-text-muted uppercase tracking-wider">
                {t('tableStatus')}
              </th>
              <th className="text-end text-xs font-medium text-text-muted uppercase tracking-wider">
                {t('tableAction')}
              </th>
            </tr>
        }
        body={
          <>
            {loading || (mode === 'search' && searching) ? (
              <tr>
                <td colSpan={5} className="py-8 text-sm text-text-secondary">
                  {tCommon('loadingEllipsis')}
                </td>
              </tr>
            ) : mode === 'existing' ? (
              existingRows.length === 0 ? (
                <tr>
                  <td colSpan={5} className="py-8 text-sm text-text-secondary">
                    {t('emptyConnections')}
                  </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="text-sm font-medium text-text-primary">
                        {row.organizationName}
                      </td>
                      <td className="text-sm text-text-secondary">{row.ownerEmail}</td>
                      <td className="text-sm text-text-secondary">
                        {formatTableDate(row.createdAt)}
                      </td>
                      <td className="text-center align-middle">
                        <Badge variant={organizationConnectionStatusVariant(row.status)} fixedWidth={false}>
                          {formatConnectionStatusLabel(row, currentOrganization.id)}
                        </Badge>
                      </td>
                      <td className="text-end">
                        <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={connectionBusy.pendingId !== null}
                                onClick={() => respondToPendingConnection(row.id, 'ACCEPT')}
                                aria-label={t('acceptRequest')}
                                title={t('acceptRequest')}
                              >
                                <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={connectionBusy.pendingId !== null}
                                onClick={() => respondToPendingConnection(row.id, 'REJECT')}
                                aria-label={t('declineRequest')}
                                title={t('declineRequest')}
                              >
                                <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={deleteBusy.pendingId !== null}
                                onClick={() => deleteConnection(row.id)}
                                aria-label={t('removeConnection')}
                                title={t('removeConnection')}
                              >
                                <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="text-sm font-medium text-text-primary">{r.name}</td>
                  <td className="text-sm text-text-secondary">{r.owner.email}</td>
                  <td className="text-sm text-text-secondary">{t('statusToday')}</td>
                  <td className="text-center align-middle">
                    <Badge variant="default" fixedWidth={false}>{t('statusFound')}</Badge>
                  </td>
                  <td className="text-end">
                    <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={connectionBusy.pendingId !== null}
                      onClick={() => submitConnectionRequest(r.id)}
                      aria-label={t('sendRequest')}
                      title={t('sendRequest')}
                    >
                      <UserPlus className="w-4 h-4" />
                    </button>
                  </td>
                </tr>
              ))
            ) : (
              <tr>
                <td colSpan={5} className="py-6">
                  <div className="flex flex-col gap-3">
                    <p className="text-sm text-text-secondary">
                      {t('noDirectoryResults')}
                    </p>
                    <div className="flex flex-wrap items-center gap-2">
                      <Button type="button" onClick={() => setShowInviteForm((v) => !v)}>
                        {showInviteForm ? t('hideInvitationFields') : t('sendInvitationLink')}
                      </Button>
                    </div>
                    {showInviteForm && (
                      <div className="grid gap-3 sm:grid-cols-3 mt-1">
                        <Input
                          label={t('counterpartNameLabel', { counterpart })}
                          value={manualOrganizationName}
                          onChange={(e) => setManualOrganizationName(e.target.value)}
                        />
                        <Input
                          label={t('ownerEmailLabel')}
                          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={() => sendInvite()}
                            className="w-full"
                          >
                            {t('sendInvitation')}
                          </Button>
                        </div>
                      </div>
                    )}
                  </div>
                </td>
              </tr>
            )}
          </>
        }
      />
      </div>

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