// Copyright: © 2026 TWWIM UG. All rights reserved. (www.twwim.com)
/**
 * MembersPage — ADMIN-only dashboard view for managing company members.
 *
 * Orchestrator only: composes InviteMemberForm + ActiveMembersList +
 * PendingInvitationsList, owns the data hook + action handlers, and renders
 * inline error/info banners. Role gating is enforced by the route's
 * beforeLoad zone guard + server-side requireCompanyAdmin middleware.
 */

import { useEffect, useState, useCallback } from 'react';
import { useNavigate } from '@tanstack/react-router';
import { Users } from 'lucide-react';
import { PageLayout } from '@/components/shared';
import { membersApi, type MemberRole } from '@/infrastructure/http/api/members/api';
import { useAuthenticatedUser } from '@/features/auth/hooks/useAuthenticatedUser';
import { useConfigurableCaps } from '@/features/subscription/hooks/useConfigurableCaps';
import { useTranslation } from '@/i18n/TranslationProvider';
import type { CompanyMemberResponse, MemberInvitationResponse } from '@archer/api-interface';
import { InviteMemberForm } from './components/InviteMemberForm';
import { ActiveMembersList } from './components/ActiveMembersList';
import { PendingInvitationsList } from './components/PendingInvitationsList';

export function MembersPage() {
  const { t } = useTranslation();
  const navigate = useNavigate();
  const user = useAuthenticatedUser();
  const companyId = user?.companyId ?? '';
  const inviterAuthId = user?.id ?? '';

  const [members, setMembers] = useState<CompanyMemberResponse[]>([]);
  const [invitations, setInvitations] = useState<MemberInvitationResponse[]>([]);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);
  const [actionError, setActionError] = useState<string | null>(null);
  const [actionInfo, setActionInfo] = useState<string | null>(null);

  // Seat-cost disclosure: shown only when MEMBERS_MAX is a paid, configurable cap.
  const { data: caps } = useConfigurableCaps();
  const seatCap = caps?.items.find((item) => item.capabilityKey === 'members_max');
  // Team is a gated plan feature: no MEMBERS_MAX cap on the plan → team disabled.
  const teamDisabled = caps !== undefined && !seatCap;
  const seatNotice =
    seatCap && seatCap.unitPrice != null
      ? t('members.invite.seatNotice', {
          used: members.length,
          limit: seatCap.currentTotal,
          price: `${seatCap.unitPrice} ${caps?.currency ?? ''}`.trim(),
        })
      : null;

  const refresh = useCallback(async () => {
    if (!companyId) return;
    setLoading(true);
    setError(null);
    try {
      const [m, inv] = await Promise.all([
        membersApi.listMembers(companyId),
        membersApi.listInvitations(companyId),
      ]);
      setMembers(m.members ?? []);
      setInvitations(inv.invitations ?? []);
    } catch (err) {
      setError(err instanceof Error ? err.message : t('members.loadFailed'));
    } finally {
      setLoading(false);
    }
  }, [companyId, t]);

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

  const handleInvite = async (email: string, role: MemberRole) => {
    if (!companyId || !inviterAuthId) return;
    setActionError(null);
    setActionInfo(null);
    try {
      // Pay-first: when the company is at its paid-seat capacity, route to the
      // SAME checkout the commands purchase uses — carrying only the non-secret
      // descriptor (invitee/role/price). The checkout creates the PaymentIntent on
      // Pay and the webhook creates the invitation after payment. Otherwise (free
      // capacity) the invitation is created now.
      const occupied = members.length + invitations.length;
      const capacity = seatCap?.currentTotal ?? null;
      const unitPrice = seatCap?.unitPrice ?? null;
      if (capacity != null && unitPrice != null && occupied >= capacity) {
        navigate({
          to: '/dashboard/checkout',
          search: { seatEmail: email, seatRole: role, seatAmount: unitPrice, seatCurrency: caps?.currency ?? 'EUR' },
        });
        return;
      }
      await membersApi.seatInvite(companyId, { email, role });
      setActionInfo(t('members.invite.sent', { email }));
      await refresh();
    } catch (err) {
      setActionError(err instanceof Error ? err.message : t('members.invite.failed'));
    }
  };

  const handleUpdateRole = async (member: CompanyMemberResponse, nextRole: MemberRole) => {
    setActionError(null);
    setActionInfo(null);
    try {
      await membersApi.updateMemberRole(companyId, member.id, nextRole);
      const name = `${member.profile.firstName} ${member.profile.lastName}`.trim();
      setActionInfo(t('members.active.roleUpdated', { name }));
      await refresh();
    } catch (err) {
      setActionError(err instanceof Error ? err.message : t('members.active.roleUpdateFailed'));
    }
  };

  const handleRemoveMember = async (member: CompanyMemberResponse) => {
    const name = `${member.profile.firstName} ${member.profile.lastName}`.trim();
    if (!confirm(t('members.active.confirmRemove', { name }))) return;
    setActionError(null);
    setActionInfo(null);
    try {
      await membersApi.removeMember(companyId, member.id);
      setActionInfo(t('members.active.removed'));
      await refresh();
    } catch (err) {
      setActionError(err instanceof Error ? err.message : t('members.active.removeFailed'));
    }
  };

  const handleTransferSeat = async (member: CompanyMemberResponse, toEmail: string) => {
    setActionError(null);
    setActionInfo(null);
    try {
      await membersApi.transferSeat(companyId, {
        fromMembershipId: member.id,
        toEmail,
        toRole: member.role as MemberRole,
      });
      setActionInfo(t('members.active.transferred'));
      await refresh();
    } catch (err) {
      setActionError(err instanceof Error ? err.message : t('members.active.transferFailed'));
    }
  };

  const handleRevokeInvitation = async (inv: MemberInvitationResponse) => {
    if (!confirm(t('members.pending.confirmRevoke', { email: inv.email }))) return;
    setActionError(null);
    setActionInfo(null);
    try {
      await membersApi.revokeInvitation(companyId, inv.id);
      setActionInfo(t('members.pending.revoked'));
      await refresh();
    } catch (err) {
      setActionError(err instanceof Error ? err.message : t('members.pending.revokeFailed'));
    }
  };

  const handleResendInvitation = async (inv: MemberInvitationResponse) => {
    setActionError(null);
    setActionInfo(null);
    try {
      await membersApi.resendInvitation(companyId, inv.id);
      setActionInfo(t('members.pending.resent', { email: inv.email }));
      await refresh();
    } catch (err) {
      setActionError(err instanceof Error ? err.message : t('members.pending.resendFailed'));
    }
  };

  return (
    <PageLayout
      title={t('members.title')}
      subtitle={t('members.subtitle')}
      icon={<Users size={24} />}
      gradient
    >
      <div className="p-6 space-y-8">
        {error && (
          <div className="rounded-md bg-red-50 border border-red-200 p-3 text-sm text-red-700" data-testid="members-error">
            {error}
          </div>
        )}
        {actionError && (
          <div className="rounded-md bg-red-50 border border-red-200 p-3 text-sm text-red-700" data-testid="members-action-error">
            {actionError}
          </div>
        )}
        {actionInfo && (
          <div className="rounded-md bg-emerald-50 border border-emerald-200 p-3 text-sm text-emerald-800" data-testid="members-action-info">
            {actionInfo}
          </div>
        )}
        {teamDisabled ? (
          <section
            data-testid="members-upgrade-cta"
            className="bg-amber-50 border border-amber-200 rounded-lg p-6"
          >
            <h2 className="text-lg font-semibold mb-1">{t('members.upgrade.title')}</h2>
            <p className="text-sm text-gray-600 mb-4">{t('members.upgrade.body')}</p>
            <a
              href="/dashboard/subscription"
              data-testid="members-upgrade-link"
              className="inline-flex items-center gap-2 bg-emerald-600 hover:bg-emerald-700 text-white font-medium rounded-md px-4 py-2 text-sm"
            >
              {t('members.upgrade.cta')}
            </a>
          </section>
        ) : (
          <InviteMemberForm onSubmit={handleInvite} seatNotice={seatNotice} />
        )}
        <ActiveMembersList
          members={members}
          loading={loading}
          onChangeRole={handleUpdateRole}
          onRemove={handleRemoveMember}
          onTransfer={handleTransferSeat}
        />
        <PendingInvitationsList
          invitations={invitations}
          onResend={handleResendInvitation}
          onRevoke={handleRevokeInvitation}
        />
      </div>
    </PageLayout>
  );
}
