/**
 * ConnectionsPage
 * 
 * Page for managing OAuth connections (Google, Microsoft) using FormGeneratorTable.
 * Follows the pattern established in AdminUsersPage/WorkflowsPage.
 */

import React, { useState, useMemo, useEffect, useRef } from 'react';
import { useConnections, type Connection } from '../../hooks/useConnections';
import { FormGeneratorTable } from '../../components/FormGenerator/FormGeneratorTable';
import { FormGeneratorForm } from '../../components/FormGenerator/FormGeneratorForm';
import { FaSync, FaLink, FaRedo, FaPlus, FaSpinner, FaTimes, FaSyncAlt } from 'react-icons/fa';
import styles from '../admin/Admin.module.css';
import bannerStyles from './ConnectionsPage.module.css';
import { AddConnectionWizard } from '../../components/AddConnectionWizard/AddConnectionWizard';
import type { ConnectorType } from '../../components/AddConnectionWizard/AddConnectionWizard';
import type { KnowledgePreferences } from '../../api/connectionApi';
import { useLanguage } from '../../providers/language/LanguageContext';
import { resolveColumnTypes } from '../../utils/columnTypeResolver';
import { getApiBaseUrl } from '../../../config/config';

const SYNC_BANNER_TTL_MS = 10 * 60 * 1000; // 10 minutes — conservative upper bound for bootstrap

export const ConnectionsPage: React.FC = () => {
    const { t } = useLanguage();

  // Use the consolidated hook
  const {
    data: connections,
    attributes,
    permissions,
    pagination,
    groupLayout,
    appliedView,
    loading,
    error,
    refetch,
    fetchConnectionById,
    updateOptimistically,
    fetchGroupSectionSummaries,
    refetchForSection,
    deleteConnection,
    handleInlineUpdate,
    createConnectionAndAuth,
    connectWithPopup,
    refreshMicrosoftToken,
    refreshGoogleToken,
    isConnecting,
  } = useConnections();

  const [editingConnection, setEditingConnection] = useState<Connection | null>(null);
  const [deletingConnections, setDeletingConnections] = useState<Set<string>>(new Set());
  const [refreshingConnections, setRefreshingConnections] = useState<Set<string>>(new Set());
  const [reconnectingConnections, setReconnectingConnections] = useState<Set<string>>(new Set());
  const [wizardOpen, setWizardOpen] = useState(false);
  // Banner shown while knowledge bootstrap is running in the background
  const [syncBanner, setSyncBanner] = useState<{
    connector: string;
    startedAt: number;
  } | null>(null);
  const syncBannerTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  const showSyncBanner = (connector: string) => {
    if (syncBannerTimer.current) clearTimeout(syncBannerTimer.current);
    setSyncBanner({ connector, startedAt: Date.now() });
    syncBannerTimer.current = setTimeout(() => setSyncBanner(null), SYNC_BANNER_TTL_MS);
  };
  const dismissSyncBanner = () => {
    if (syncBannerTimer.current) clearTimeout(syncBannerTimer.current);
    setSyncBanner(null);
  };

  // Initial fetch
  useEffect(() => {
    refetch();
  }, []);

  // Generate columns from attributes - hide internal/redundant fields
  const columns = useMemo(() => {
    const hiddenColumns = ['id', 'externalId', 'tokenStatus', 'tokenExpiresAt', 'grantedScopes'];

    const raw = (attributes || [])
      .filter(attr => !hiddenColumns.includes(attr.name))
      .map(attr => {
        const col: any = {
          key: attr.name,
          label: attr.name === 'userId' ? t('Benutzer') : attr.label || attr.name,
          sortable: attr.sortable !== false,
          filterable: attr.filterable !== false,
          searchable: attr.searchable !== false,
          width: attr.width || 150,
          minWidth: attr.minWidth || 100,
          maxWidth: attr.maxWidth || 400,
          displayField: (attr as any).displayField,
          frontendFormat: (attr as any).frontendFormat,
          frontendFormatLabels: (attr as any).frontendFormatLabels,
        };
        return col;
      });
    return resolveColumnTypes(raw, attributes || []);
  }, [attributes, t]);

  // Check permissions
  const canCreate = permissions?.create !== 'n';
  const canUpdate = permissions?.update !== 'n';
  const canDelete = permissions?.delete !== 'n';

  // Handle edit click
  const handleEditClick = async (connection: Connection) => {
    const fullConnection = await fetchConnectionById(connection.id);
    if (fullConnection) {
      setEditingConnection(fullConnection as Connection);
    }
  };

  // Handle edit submit
  const handleEditSubmit = async (data: Partial<Connection>) => {
    if (!editingConnection) return;
    try {
      const updateData: Partial<import('../../api/connectionApi').Connection> = { ...data };

      // Strip computed/read-only fields the backend cannot write.
      delete (updateData as any).connectionReference;
      delete (updateData as any).displayLabel;
      delete (updateData as any).tokenStatus;
      delete (updateData as any).tokenExpiresAt;

      if (data.authority) {
        if (
          data.authority === 'local' ||
          data.authority === 'google' ||
          data.authority === 'msft' ||
          data.authority === 'clickup' ||
          data.authority === 'infomaniak'
        ) {
          updateData.authority = data.authority;
        } else {
          delete (updateData as any).authority;
        }
      }
      
      await handleInlineUpdate(editingConnection.id, updateData, editingConnection);
      setEditingConnection(null);
      refetch();
    } catch (error) {
      console.error('Error updating connection:', error);
    }
  };

  // Handle delete (confirmation handled by DeleteActionButton)
  const handleDelete = async (connection: Connection) => {
    setDeletingConnections(prev => new Set(prev).add(connection.id));
    try {
      await deleteConnection(connection.id);
      refetch();
    } catch (error) {
      console.error('Error deleting connection:', error);
    } finally {
      setDeletingConnections(prev => {
        const newSet = new Set(prev);
        newSet.delete(connection.id);
        return newSet;
      });
    }
  };

  // Handle connect
  const handleConnect = async (connection: Connection) => {
    try {
      await connectWithPopup(connection.id);
      refetch();
    } catch (error) {
      console.error('Error connecting:', error);
    }
  };

  // Handle refresh token
  const handleRefresh = async (connection: Connection) => {
    setRefreshingConnections(prev => new Set(prev).add(connection.id));
    try {
      if (connection.authority === 'msft') {
        await refreshMicrosoftToken(connection.id);
      } else if (connection.authority === 'google') {
        await refreshGoogleToken(connection.id);
      }
      refetch();
    } catch (error) {
      console.error('Error refreshing token:', error);
    } finally {
      setRefreshingConnections(prev => {
        const newSet = new Set(prev);
        newSet.delete(connection.id);
        return newSet;
      });
    }
  };

  // Handle reconnect (full OAuth re-consent so newly added scopes -- e.g.
  // Calendar/Contacts -- are actually granted on top of existing tokens).
  const handleReconnect = async (connection: Connection) => {
    setReconnectingConnections(prev => new Set(prev).add(connection.id));
    try {
      await connectWithPopup(connection.id, true);
      refetch();
    } catch (error) {
      console.error('Error reconnecting:', error);
    } finally {
      setReconnectingConnections(prev => {
        const newSet = new Set(prev);
        newSet.delete(connection.id);
        return newSet;
      });
    }
  };

  const handleWizardConnect = async (
    type: ConnectorType,
    knowledgeEnabled: boolean,
    knowledgePreferences?: KnowledgePreferences | null,
  ) => {
    try {
      await createConnectionAndAuth(type, knowledgeEnabled, knowledgePreferences ?? null);
      refetch();
      if (knowledgeEnabled) {
        const LABELS: Record<ConnectorType, string> = { google: 'Google', msft: 'Microsoft 365', clickup: 'ClickUp', infomaniak: 'Infomaniak' };
        showSyncBanner(LABELS[type] ?? type);
      }
    } catch (error) {
      console.error('Error creating connection via wizard:', error);
    }
  };

  const handleMsftAdminConsent = () => {
    const url = `${getApiBaseUrl()}/api/msft/adminconsent`;
    window.open(url, 'msft-admin-consent', 'width=560,height=720,scrollbars=yes,resizable=yes');
  };

  // Form attributes for edit modal
  const formAttributes = useMemo(() => {
    const excludedFields = [
      'id', 'mandateId', 'userId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt',
      'connectedAt', 'lastChecked',
      // computed/read-only fields the backend rejects on write
      'connectionReference', 'displayLabel', 'tokenStatus', 'tokenExpiresAt',
    ];
    return (attributes || [])
      .filter(attr => !excludedFields.includes(attr.name));
  }, [attributes]);

  if (error) {
    return (
      <div className={styles.adminPage}>
        <div className={styles.errorContainer}>
          <span className={styles.errorIcon}>⚠️</span>
          <p className={styles.errorMessage}>{t('Fehler beim Laden der Verbindungen: {detail}', { detail: String(error) })}</p>
          <button className={styles.secondaryButton} onClick={() => refetch()}>
            <FaSync /> {t('Erneut versuchen')}
          </button>
        </div>
      </div>
    );
  }

  return (
    <div className={`${styles.adminPage} ${styles.adminPageFill}`}>
      <div className={styles.pageHeader}>
        <div>
          <h1 className={styles.pageTitle}>{t('Verbindungen')}</h1>
          <p className={styles.pageSubtitle}>
            {t('Persönliche Datenanbindungen verwalten (OAuth: Google, Microsoft, ClickUp, Infomaniak)')}
          </p>
        </div>
        <div className={styles.headerActions}>
          <button 
            className={styles.secondaryButton} 
            onClick={() => refetch()}
            disabled={loading}
          >
            <FaSync className={loading ? 'spinning' : ''} /> {t('Aktualisieren')}
          </button>
          {canCreate && (
            <button
              type="button"
              className={styles.primaryButton}
              onClick={() => setWizardOpen(true)}
              disabled={isConnecting}
            >
              <FaPlus /> {t('Verbindung hinzufügen')}
            </button>
          )}
        </div>
      </div>

      {/* Sync-in-progress banner */}
      {syncBanner && (
        <div className={bannerStyles.syncBanner}>
          <FaSpinner className={bannerStyles.syncSpinner} />
          <div className={bannerStyles.syncText}>
            <span className={bannerStyles.syncTitle}>
              {t('Wissensdatenbank wird synchronisiert')}
            </span>
            <span className={bannerStyles.syncDetail}>
              {t(
                'Inhalte aus {connector} werden im Hintergrund indexiert. Das kann je nach Datenmenge einige Minuten dauern. Die Wissensdatenbank steht danach vollständig zur Verfügung.',
                { connector: syncBanner.connector },
              )}
            </span>
          </div>
          <button
            type="button"
            className={bannerStyles.syncDismiss}
            onClick={dismissSyncBanner}
            aria-label={t('Hinweis schließen')}
          >
            <FaTimes />
          </button>
        </div>
      )}

      <div className={styles.tableContainer}>
        <FormGeneratorTable
            data={connections}
            columns={columns}
            apiEndpoint="/api/connections/"
            tableContextKey="connections"
            tableGroupLayoutMode="inline"
            loading={loading}
            pagination={true}
            pageSize={25}
            searchable={true}
            filterable={true}
            sortable={true}
            selectable={true}
            actionButtons={[
              ...(canUpdate ? [{
                type: 'edit' as const,
                onAction: handleEditClick,
                title: t('Bearbeiten'),
              }] : []),
              ...(canDelete ? [{
                type: 'delete' as const,
                title: t('Löschen'),
                loading: (row: Connection) => deletingConnections.has(row.id),
              }] : []),
            ]}
            customActions={[
              {
                id: 'connect',
                icon: <FaLink />,
                onClick: handleConnect,
                title: t('Verbinden'),
                visible: (row: Connection) => row.status !== 'active',
                loading: () => isConnecting,
              },
              {
                id: 'refresh',
                icon: <FaRedo />,
                onClick: handleRefresh,
                title: t('Token aktualisieren'),
                visible: (row: Connection) => row.status === 'active' && (row.authority === 'msft' || row.authority === 'google'),
                loading: (row: Connection) => refreshingConnections.has(row.id),
              },
              {
                id: 'reconnect',
                icon: <FaSyncAlt />,
                onClick: handleReconnect,
                title: t('Erneut verbinden (neue Scopes erteilen)'),
                visible: (row: Connection) =>
                  row.status === 'active' &&
                  (row.authority === 'msft' || row.authority === 'google' || row.authority === 'clickup'),
                loading: (row: Connection) => reconnectingConnections.has(row.id),
              },
            ]}
            onDelete={handleDelete}
            hookData={{
              refetch,
              permissions,
              pagination,
              groupLayout,
              appliedView,
              handleDelete: deleteConnection,
              handleInlineUpdate,
              updateOptimistically,
              fetchGroupSectionSummaries,
              refetchForSection,
            }}
            emptyMessage={t('Keine Verbindungen gefunden')}
          />
      </div>

      {/* Edit Modal */}
      {editingConnection && (
        <div className={styles.modalOverlay}>
          <div className={styles.modal}>
            <div className={styles.modalHeader}>
              <h2 className={styles.modalTitle}>{t('Verbindung bearbeiten')}</h2>
              <button 
                className={styles.modalClose}
                onClick={() => setEditingConnection(null)}
              >
                ✕
              </button>
            </div>
            <div className={styles.modalContent}>
              {formAttributes.length === 0 ? (
                <div className={styles.loadingContainer}>
                  <div className={styles.spinner} />
                  <span>{t('Formular laden')}</span>
                </div>
              ) : (
                <FormGeneratorForm
                  attributes={formAttributes}
                  data={editingConnection}
                  mode="edit"
                  onSubmit={handleEditSubmit}
                  onCancel={() => setEditingConnection(null)}
                  submitButtonText={t('Speichern')}
                  cancelButtonText={t('Abbrechen')}
                />
              )}
            </div>
          </div>
        </div>
      )}

      <AddConnectionWizard
        open={wizardOpen}
        onClose={() => setWizardOpen(false)}
        onConnect={handleWizardConnect}
        onMsftAdminConsent={handleMsftAdminConsent}
        isConnecting={isConnecting}
      />
    </div>
  );
};

export default ConnectionsPage;
