/**
 * NeutralizationView
 *
 * Combined view for the Neutralization feature with two tabs:
 * - Configuration: Configure names to parse.
 * - Playground: Upload file, paste text, or neutralize SharePoint files. Resolve placeholders.
 */

import React, { useState, useEffect, useCallback } from 'react';
import { useCurrentInstance } from '../../../hooks/useCurrentInstance';
import { useToast } from '../../../contexts/ToastContext';
import { useFileContext } from '../../../contexts/FileContext';
import { useConnections, type Connection } from '../../../hooks/useConnections';
import {
  getNeutralizationConfig,
  saveNeutralizationConfig,
  processSharepointFiles,
  neutralizeText,
  neutralizeFile,
  resolveText,
  type NeutralizationConfig,
} from '../../../api/neutralizationApi';
import { Tabs } from '../../../components/UiComponents/Tabs';
import api from '../../../api';
import styles from './NeutralizationViews.module.css';

interface SiteOption {
  value: string;
  label: string;
  siteId: string;
  siteName: string;
  webUrl: string;
  path: string;
}

interface FolderOption {
  value: string;
  label: string;
  siteId: string;
  folderName: string;
  path: string;
}

// =============================================================================
// CONFIGURATION TAB
// =============================================================================

const ConfigTab: React.FC = () => {
  const { instance } = useCurrentInstance();
  const { showSuccess, showError } = useToast();

  const [config, setConfig] = useState<NeutralizationConfig | null>(null);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const [enabled, setEnabled] = useState(true);
  const [namesToParse, setNamesToParse] = useState('');

  const loadConfig = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const data = await getNeutralizationConfig();
      setConfig(data);
      setEnabled(data.enabled);
      setNamesToParse(data.namesToParse || '');
    } catch (err: unknown) {
      const errObj = err as { response?: { data?: { detail?: string | { msg?: string }[] } }; message?: string };
      const detail = errObj.response?.data?.detail;
      const message =
        (typeof detail === 'string' ? detail : null) ||
        (Array.isArray(detail) ? detail.map((e: { msg?: string }) => e.msg || JSON.stringify(e)).join(', ') : null) ||
        errObj.message ||
        'Error loading configuration';
      setError(message);
      showError('Error', message);
    } finally {
      setLoading(false);
    }
  }, [showError]);

  useEffect(() => {
    loadConfig();
  }, [loadConfig]);

  const handleSave = async () => {
    setSaving(true);
    setError(null);
    try {
      const mandateId = instance?.mandateId;
      const featureInstanceId = instance?.id;
      if (!mandateId || !featureInstanceId) {
        throw new Error('Missing mandate or instance context');
      }
      await saveNeutralizationConfig({
        mandateId,
        featureInstanceId,
        userId: config?.userId || '',
        enabled,
        namesToParse,
        sharepointSourcePath: config?.sharepointSourcePath || '',
        sharepointTargetPath: config?.sharepointTargetPath || '',
      });
      showSuccess('Saved', 'Configuration saved successfully.');
      await loadConfig();
    } catch (err: unknown) {
      const errObj = err as { response?: { data?: { detail?: string } }; message?: string };
      const message =
        (typeof errObj.response?.data?.detail === 'string' ? errObj.response.data.detail : null) ||
        errObj.message ||
        'Failed to save configuration';
      setError(message);
      showError('Error', message);
    } finally {
      setSaving(false);
    }
  };

  const dismissError = () => setError(null);

  if (loading) {
    return <div className={styles.loading}>Loading configuration...</div>;
  }

  return (
    <div className={styles.configSection}>
      <h3 className={styles.sectionTitle}>Neutralization Configuration</h3>
      <p className={styles.sectionDescription}>
        Configure data neutralization settings for this instance.
      </p>

      <div className={styles.configCard}>
        {error && (
          <div className={styles.errorMessage}>
            <span>{error}</span>
            <button type="button" onClick={dismissError} aria-label="Dismiss">
              ×
            </button>
          </div>
        )}

        <div className={styles.formRow}>
          <label htmlFor="names-to-parse">Names to Parse (one per line):</label>
          <textarea
            id="names-to-parse"
            className={styles.textareaField}
            value={namesToParse}
            onChange={(e) => setNamesToParse(e.target.value)}
            placeholder="Enter names to parse, one per line..."
            rows={6}
          />
        </div>

        <div className={styles.buttonRow}>
          <button
            type="button"
            className={styles.primaryButton}
            onClick={handleSave}
            disabled={saving}
          >
            {saving ? 'Saving...' : 'Save Configuration'}
          </button>
        </div>
      </div>
    </div>
  );
};

// =============================================================================
// PLAYGROUND TAB
// =============================================================================

const PlaygroundTab: React.FC = () => {
  const { showSuccess, showError } = useToast();
  const { refetch: refetchFiles, handleFileDownload } = useFileContext();
  const { connections } = useConnections();

  const msftConnections = connections.filter(
    (c: Connection) => (c.authority === 'msft' || c.type === 'msft') && c.status === 'active'
  );
  const hasMsftConnection = msftConnections.length > 0;
  const msftConnection = msftConnections[0] ?? null;

  const [inputText, setInputText] = useState('');
  const [neutralizedText, setNeutralizedText] = useState('');
  const [neutralizing, setNeutralizing] = useState(false);
  const [resolving, setResolving] = useState(false);
  const [sharepointSourcePath, setSharepointSourcePath] = useState('');
  const [sharepointTargetPath, setSharepointTargetPath] = useState('');
  const [processingSharepoint, setProcessingSharepoint] = useState(false);

  const [browseTarget, setBrowseTarget] = useState<'source' | 'target' | null>(null);
  const [siteOptions, setSiteOptions] = useState<SiteOption[]>([]);
  const [folderOptions, setFolderOptions] = useState<FolderOption[]>([]);
  const [selectedSite, setSelectedSite] = useState<SiteOption | null>(null);
  const [browseCurrentPath, setBrowseCurrentPath] = useState('');
  const [isLoadingSites, setIsLoadingSites] = useState(false);
  const [isLoadingFolders, setIsLoadingFolders] = useState(false);
  const [browseError, setBrowseError] = useState<string | null>(null);

  const getConnectionReference = useCallback((conn: Connection): string => {
    return conn.connectionReference || `connection:${conn.authority || conn.type}:${conn.externalUsername}`;
  }, []);

  const loadSiteOptions = useCallback(async () => {
    if (!msftConnection) return;
    setIsLoadingSites(true);
    setBrowseError(null);
    try {
      const ref = getConnectionReference(msftConnection);
      const params = new URLSearchParams({ connectionReference: ref });
      const response = await api.get(`/api/sharepoint/folder-options?${params}`);
      setSiteOptions(response.data || []);
    } catch (err: unknown) {
      const detail = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail;
      setBrowseError(typeof detail === 'string' ? detail : 'Failed to load SharePoint sites');
      setSiteOptions([]);
    } finally {
      setIsLoadingSites(false);
    }
  }, [msftConnection, getConnectionReference]);

  const loadFolderOptions = useCallback(async (siteId: string, path: string = '') => {
    if (!msftConnection || !siteId) return;
    setIsLoadingFolders(true);
    setBrowseError(null);
    try {
      const ref = getConnectionReference(msftConnection);
      const params = new URLSearchParams({ connectionReference: ref, siteId });
      if (path) params.append('path', path);
      const response = await api.get(`/api/sharepoint/folder-options?${params}`);
      setFolderOptions(response.data || []);
    } catch (err: unknown) {
      const detail = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail;
      setBrowseError(typeof detail === 'string' ? detail : 'Failed to load folders');
      setFolderOptions([]);
    } finally {
      setIsLoadingFolders(false);
    }
  }, [msftConnection, getConnectionReference]);

  const handleOpenBrowse = useCallback((target: 'source' | 'target') => {
    setBrowseTarget(target);
    setSelectedSite(null);
    setBrowseCurrentPath('');
    setFolderOptions([]);
    setBrowseError(null);
    loadSiteOptions();
  }, [loadSiteOptions]);

  const handleCloseBrowse = useCallback(() => {
    setBrowseTarget(null);
    setSelectedSite(null);
    setBrowseCurrentPath('');
  }, []);

  const handleSiteChange = useCallback((siteId: string) => {
    const site = siteOptions.find((s) => s.siteId === siteId) || null;
    setSelectedSite(site);
    setBrowseCurrentPath('');
    if (site) {
      loadFolderOptions(site.siteId, '');
    } else {
      setFolderOptions([]);
    }
  }, [siteOptions, loadFolderOptions]);

  const handleFolderNavigate = useCallback((folder: FolderOption) => {
    setBrowseCurrentPath(folder.path);
    loadFolderOptions(selectedSite!.siteId, folder.path);
  }, [selectedSite, loadFolderOptions]);

  const handleFolderSelect = useCallback((folder: FolderOption) => {
    if (!selectedSite) return;
    const fullPath = selectedSite.webUrl + (folder.path ? '/' + folder.path : '');
    if (browseTarget === 'source') setSharepointSourcePath(fullPath);
    else setSharepointTargetPath(fullPath);
    handleCloseBrowse();
  }, [selectedSite, browseTarget, handleCloseBrowse]);

  const handleSelectCurrentFolder = useCallback(() => {
    if (!selectedSite) return;
    const fullPath = selectedSite.webUrl + (browseCurrentPath ? '/' + browseCurrentPath : '');
    if (browseTarget === 'source') setSharepointSourcePath(fullPath);
    else setSharepointTargetPath(fullPath);
    handleCloseBrowse();
  }, [selectedSite, browseCurrentPath, browseTarget, handleCloseBrowse]);

  const handleGoUp = useCallback(() => {
    if (!browseCurrentPath || !selectedSite) return;
    const parts = browseCurrentPath.split('/');
    parts.pop();
    const parentPath = parts.join('/');
    setBrowseCurrentPath(parentPath);
    loadFolderOptions(selectedSite.siteId, parentPath);
  }, [browseCurrentPath, selectedSite, loadFolderOptions]);

  useEffect(() => {
    let mounted = true;
    getNeutralizationConfig()
      .then((data) => {
        if (mounted) {
          setSharepointSourcePath(data.sharepointSourcePath || '');
          setSharepointTargetPath(data.sharepointTargetPath || '');
        }
      })
      .catch(() => {});
    return () => { mounted = false; };
  }, []);
  const [fileResult, setFileResult] = useState<{
    base64?: string;
    fileName?: string;
    mimeType?: string;
    fileId?: string;
  } | null>(null);
  const fileInputRef = React.useRef<HTMLInputElement>(null);

  const handleNeutralize = async () => {
    if (!inputText.trim()) {
      showError('Error', 'Please enter text to neutralize.');
      return;
    }
    setNeutralizing(true);
    setFileResult(null);
    try {
      const result = await neutralizeText(inputText);
      setNeutralizedText(result.neutralized_text || '');
      showSuccess('Done', 'Text neutralized successfully.');
    } catch (err: unknown) {
      const errObj = err as { response?: { data?: { detail?: string } }; message?: string };
      const message =
        (typeof errObj.response?.data?.detail === 'string' ? errObj.response.data.detail : null) ||
        errObj.message ||
        'Failed to neutralize text';
      showError('Error', message);
    } finally {
      setNeutralizing(false);
    }
  };

  const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    setNeutralizing(true);
    setFileResult(null);
    setNeutralizedText('');
    try {
      const result = await neutralizeFile(file);
      const base64Data = result.neutralized_file_base64 || (typeof result.neutralized_bytes === 'string' ? result.neutralized_bytes : null);
      const fileName = result.neutralized_file_name || `neutralized_${file.name}`;
      if (base64Data) {
        setFileResult({
          base64: base64Data,
          fileName,
          mimeType: result.mime_type || 'application/octet-stream',
          fileId: result.neutralized_file_id,
        });
        setNeutralizedText('');
        showSuccess('Done', 'File neutralized. Download below or find it in your Files.');
      } else if (result.neutralized_text !== undefined) {
        setNeutralizedText(result.neutralized_text || '');
        setFileResult(result.neutralized_file_id ? { fileName, fileId: result.neutralized_file_id } : { fileName });
        showSuccess('Done', result.neutralized_file_id ? 'File neutralized. Download or find in Files.' : 'File neutralized.');
      } else {
        const err = (result.processed_info as { error?: string })?.error || 'No result returned';
        console.warn('[Neutralization] Unexpected result:', result);
        showError('Error', err);
      }
      if (result.original_file_id || result.neutralized_file_id) {
        refetchFiles();
      }
    } catch (err: unknown) {
      const errObj = err as { response?: { data?: { detail?: string } }; message?: string };
      const message =
        (typeof errObj.response?.data?.detail === 'string' ? errObj.response.data.detail : null) ||
        errObj.message ||
        'Failed to neutralize file';
      showError('Error', message);
    } finally {
      setNeutralizing(false);
      e.target.value = '';
    }
  };

  const handleDownload = async () => {
    if (!fileResult?.fileName) return;
    if (fileResult.fileId) {
      try {
        await handleFileDownload(fileResult.fileId, fileResult.fileName);
      } catch {
        showError('Error', 'Failed to download file');
      }
      return;
    }
    if (fileResult.base64) {
      try {
        const bin = atob(fileResult.base64);
        const bytes = new Uint8Array(bin.length);
        for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
        const blob = new Blob([bytes], { type: fileResult.mimeType || 'application/octet-stream' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = fileResult.fileName;
        a.click();
        URL.revokeObjectURL(url);
      } catch (e) {
        showError('Error', 'Failed to download file');
      }
      return;
    }
    if (neutralizedText) {
      const blob = new Blob([neutralizedText], { type: 'text/plain;charset=utf-8' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = fileResult.fileName;
      a.click();
      URL.revokeObjectURL(url);
      return;
    }
    showError('Error', 'No file data available to download. The neutralized file may not have been generated.');
  };

  const handleResolve = async () => {
    if (!neutralizedText.trim()) {
      showError('Error', 'No neutralized text to resolve.');
      return;
    }
    setResolving(true);
    try {
      const result = await resolveText(neutralizedText);
      setNeutralizedText(result.resolved_text || '');
      showSuccess('Done', 'Text resolved successfully.');
    } catch (err: unknown) {
      const errObj = err as { response?: { data?: { detail?: string } }; message?: string };
      const message =
        (typeof errObj.response?.data?.detail === 'string' ? errObj.response.data.detail : null) ||
        errObj.message ||
        'Failed to resolve text';
      showError('Error', message);
    } finally {
      setResolving(false);
    }
  };

  const handleClear = () => {
    setNeutralizedText('');
    setFileResult(null);
  };

  const handleProcessSharepoint = async () => {
    if (!sharepointSourcePath.trim() || !sharepointTargetPath.trim()) {
      showError('Error', 'Both SharePoint source and target paths are required.');
      return;
    }
    setProcessingSharepoint(true);
    try {
      const result = await processSharepointFiles(sharepointSourcePath, sharepointTargetPath);
      if (result.success) {
        showSuccess('Done', result.message || 'SharePoint files processed successfully.');
      } else {
        showError('Error', result.message || 'Processing failed');
      }
    } catch (err: unknown) {
      const errObj = err as { response?: { data?: { detail?: string } }; message?: string };
      const message =
        (typeof errObj.response?.data?.detail === 'string' ? errObj.response.data.detail : null) ||
        errObj.message ||
        'Failed to process SharePoint files';
      showError('Error', message);
    } finally {
      setProcessingSharepoint(false);
    }
  };

  return (
    <>
    <div className={styles.playgroundSection}>
      <h3 className={styles.sectionTitle}>Manual Text &amp; File Neutralization</h3>
      <p className={styles.sectionDescription}>
        Upload a file, paste text, or neutralize SharePoint files. Use &quot;Resolve Text&quot; to convert placeholders back to the original text.
      </p>

      <div className={styles.playgroundCard}>
        <div className={styles.formRow}>
          <label>1. Upload file to neutralize:</label>
          <input
            ref={fileInputRef}
            type="file"
            accept=".pdf,.docx,.xlsx,.xlsm,.pptx,.txt,.csv,.json"
            onChange={handleFileSelect}
            style={{ display: 'none' }}
          />
          <div className={styles.buttonRow}>
            <button
              type="button"
              className={styles.primaryButton}
              onClick={() => fileInputRef.current?.click()}
              disabled={neutralizing}
            >
              {neutralizing ? 'Processing...' : 'Upload & Neutralize File'}
            </button>
            {fileResult && (
              <button
                type="button"
                className={styles.primaryButton}
                onClick={handleDownload}
              >
                Download {fileResult.fileName || 'Neutralized File'}
              </button>
            )}
          </div>
          {fileResult?.fileId && (
            <p className={styles.sectionDescription} style={{ marginTop: 4, marginBottom: 0 }}>
              File saved to your Files. You can also download it from Basisdaten → Files.
            </p>
          )}
        </div>

        <div className={styles.formRow}>
          <label htmlFor="input-text">2. Or paste text:</label>
          <textarea
            id="input-text"
            className={styles.textareaField}
            value={inputText}
            onChange={(e) => setInputText(e.target.value)}
            placeholder="Enter text to neutralize..."
            rows={6}
          />
        </div>
        <div className={styles.buttonRow}>
          <button
            type="button"
            className={styles.primaryButton}
            onClick={handleNeutralize}
            disabled={neutralizing}
          >
            {neutralizing ? 'Neutralizing...' : 'Neutralize Text'}
          </button>
          <button
            type="button"
            className={styles.secondaryButton}
            onClick={handleResolve}
            disabled={resolving || !neutralizedText.trim()}
          >
            {resolving ? 'Resolving...' : 'Resolve Text'}
          </button>
        </div>

        <div className={styles.formRow}>
          <label>3. Or neutralize SharePoint files:</label>
          <div className={styles.formRow} style={{ gap: '0.75rem', marginTop: 0 }}>
            <div>
              <label htmlFor="sharepoint-source" style={{ fontSize: '0.8125rem', fontWeight: 400 }}>Source:</label>
              <div className={styles.inputWithButton}>
                <input
                  id="sharepoint-source"
                  type="text"
                  value={sharepointSourcePath}
                  onChange={(e) => setSharepointSourcePath(e.target.value)}
                  placeholder="SharePoint source path..."
                />
                <button
                  type="button"
                  className={styles.secondaryButton}
                  onClick={() => handleOpenBrowse('source')}
                  disabled={!hasMsftConnection}
                  title={hasMsftConnection ? 'Browse SharePoint' : 'Add a Microsoft connection first (Basisdaten → Connections)'}
                >
                  Browse
                </button>
              </div>
            </div>
            <div>
              <label htmlFor="sharepoint-target" style={{ fontSize: '0.8125rem', fontWeight: 400 }}>Target:</label>
              <div className={styles.inputWithButton}>
                <input
                  id="sharepoint-target"
                  type="text"
                  value={sharepointTargetPath}
                  onChange={(e) => setSharepointTargetPath(e.target.value)}
                  placeholder="SharePoint target path..."
                />
                <button
                  type="button"
                  className={styles.secondaryButton}
                  onClick={() => handleOpenBrowse('target')}
                  disabled={!hasMsftConnection}
                  title={hasMsftConnection ? 'Browse SharePoint' : 'Add a Microsoft connection first (Basisdaten → Connections)'}
                >
                  Browse
                </button>
              </div>
            </div>
          </div>
          <div className={styles.buttonRow}>
            <button
              type="button"
              className={styles.secondaryButton}
              onClick={handleProcessSharepoint}
              disabled={processingSharepoint || !sharepointSourcePath.trim() || !sharepointTargetPath.trim()}
              title={
                !sharepointSourcePath.trim() || !sharepointTargetPath.trim()
                  ? 'Enter source and target SharePoint paths to enable'
                  : undefined
              }
            >
              {processingSharepoint ? 'Processing...' : 'Neutralize SharePoint Files'}
            </button>
          </div>
        </div>

        {neutralizedText && !fileResult && (
          <div className={styles.formRow}>
            <label htmlFor="neutralized-text">Neutralized Text:</label>
            <div
              id="neutralized-text"
              className={styles.outputBlock}
              role="region"
              aria-live="polite"
            >
              {neutralizedText}
            </div>
          </div>
        )}

        {(neutralizedText || fileResult) && (
          <button
            type="button"
            className={styles.clearLink}
            onClick={handleClear}
          >
            Clear Result
          </button>
        )}
      </div>
    </div>

    {browseTarget && (
      <div className={styles.modalOverlay} onClick={handleCloseBrowse}>
        <div className={styles.modalContent} onClick={(e) => e.stopPropagation()}>
          <h3 className={styles.modalTitle}>
            Browse SharePoint {browseTarget === 'source' ? 'Source' : 'Target'} Folder
          </h3>
          {browseError && (
            <div className={styles.errorMessage} style={{ marginBottom: '0.75rem' }}>
              {browseError}
            </div>
          )}
          {isLoadingSites ? (
            <div className={styles.loading}>Loading sites...</div>
          ) : (
            <>
              <label htmlFor="browse-site" style={{ fontSize: '0.875rem', fontWeight: 500 }}>Site:</label>
              <select
                id="browse-site"
                className={styles.folderSelect}
                value={selectedSite?.siteId || ''}
                onChange={(e) => handleSiteChange(e.target.value)}
              >
                <option value="">Select a site...</option>
                {siteOptions.map((site) => (
                  <option key={site.siteId} value={site.siteId}>
                    {site.label}
                  </option>
                ))}
              </select>
            </>
          )}
          {selectedSite && (
            <>
              <p style={{ fontSize: '0.875rem', color: 'var(--text-secondary)', margin: '0 0 0.5rem 0' }}>
                Current path: <strong>{selectedSite.path}{browseCurrentPath ? '/' + browseCurrentPath : ''}</strong>
              </p>
              {isLoadingFolders ? (
                <div className={styles.loading}>Loading folders...</div>
              ) : (
                <div>
                  <div style={{ display: 'flex', gap: '0.5rem', marginBottom: '0.5rem' }}>
                    {browseCurrentPath && (
                      <button type="button" className={styles.secondaryButton} onClick={handleGoUp}>
                        ↑ Go Up
                      </button>
                    )}
                    <button
                      type="button"
                      className={styles.primaryButton}
                      onClick={handleSelectCurrentFolder}
                    >
                      Select This Folder
                    </button>
                  </div>
                  <div className={styles.folderList}>
                    {folderOptions.map((folder) => (
                      <div key={folder.value} className={styles.folderItem}>
                        <span
                          className={styles.folderName}
                          onClick={() => handleFolderNavigate(folder)}
                        >
                          📁 {folder.label}
                        </span>
                        <button
                          type="button"
                          className={styles.selectButton}
                          onClick={(e) => { e.stopPropagation(); handleFolderSelect(folder); }}
                        >
                          Select
                        </button>
                      </div>
                    ))}
                    {folderOptions.length === 0 && (
                      <div style={{ padding: '0.75rem', color: 'var(--text-secondary)', fontSize: '0.875rem' }}>
                        No subfolders in this location
                      </div>
                    )}
                  </div>
                </div>
              )}
            </>
          )}
          <div style={{ marginTop: '1rem' }}>
            <button type="button" className={styles.secondaryButton} onClick={handleCloseBrowse}>
              Cancel
            </button>
          </div>
        </div>
      </div>
    )}
    </>
  );
};

// =============================================================================
// MAIN VIEW
// =============================================================================

const TABS = [
  { id: 'config', label: 'Configuration', content: <ConfigTab /> },
  { id: 'playground', label: 'Playground', content: <PlaygroundTab /> },
];

export const NeutralizationView: React.FC = () => {
  return (
    <Tabs tabs={TABS} defaultTabId="playground" />
  );
};

export default NeutralizationView;
