/**
 * AccessRulesEditor
 * 
 * Main component for editing RBAC access rules for a role.
 * Provides tabbed interface for DATA, UI, and RESOURCE rules.
 * 
 * Features:
 * - Checkbox-based compact table for DATA rules
 * - Card view for UI/RESOURCE rules
 * - Object catalog dropdown for adding new rules
 */

import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { 
  FaTable, 
  FaDesktop, 
  FaServer, 
  FaCode, 
  FaPlus, 
  FaTrash, 
  FaSave,
  FaUndo,
  FaSpinner,
  FaThList,
  FaTh,
} from 'react-icons/fa';
import { useToast } from '../../contexts/ToastContext';
import { 
  useAccessRules, 
  type AccessRule, 
  type RuleContext, 
  type AccessLevel,
  type AccessRuleCreate,
} from '../../hooks/useAccessRules';
import { useCatalogObjects, type CatalogObject } from '../../hooks/useCatalogObjects';
import { AccessLevelSelect } from './AccessLevelSelect';
import { AccessRulesTable } from './AccessRulesTable';
import styles from './AccessRules.module.css';

// =============================================================================
// TYPES
// =============================================================================

interface AccessRulesEditorProps {
  roleId: string;
  roleName?: string;
  isTemplate?: boolean;
  readOnly?: boolean;
  onSave?: () => void;
  apiBasePath?: string;
  mandateId?: string;
  featureCode?: string; // Filter catalog objects to this feature only
}

type TabType = 'DATA' | 'UI' | 'RESOURCE' | 'JSON';

// =============================================================================
// RULE CARD COMPONENT
// =============================================================================

interface RuleCardProps {
  rule: AccessRule;
  readOnly?: boolean;
  onUpdate: (ruleId: string, updates: Partial<AccessRule>) => void;
  onDelete: (ruleId: string) => void;
}

const RuleCard: React.FC<RuleCardProps> = ({ rule, readOnly, onUpdate, onDelete }) => {
  const isDataRule = rule.context === 'DATA';
  
  return (
    <div className={styles.ruleCard}>
      <div className={styles.ruleHeader}>
        <div className={styles.ruleItem}>
          <span className={styles.ruleItemIcon}>
            {rule.context === 'DATA' ? <FaTable /> : 
             rule.context === 'UI' ? <FaDesktop /> : <FaServer />}
          </span>
          <span className={styles.ruleItemName}>{rule.item || '(global)'}</span>
        </div>
        {!readOnly && (
          <div className={styles.ruleActions}>
            <button
              className={`${styles.iconButton} ${styles.danger}`}
              onClick={() => onDelete(rule.id)}
              title="Regel löschen"
            >
              <FaTrash />
            </button>
          </div>
        )}
      </div>
      
      <div className={styles.permissionsGrid}>
        {/* View Toggle */}
        <div className={styles.permissionItem}>
          <span className={styles.permissionLabel}>View</span>
          <div className={styles.viewToggle}>
            <input
              type="checkbox"
              checked={rule.view}
              onChange={(e) => onUpdate(rule.id, { view: e.target.checked })}
              disabled={readOnly}
              className={styles.viewCheckbox}
            />
          </div>
        </div>
        
        {/* CRUD Levels (only for DATA context) */}
        {isDataRule ? (
          <>
            <div className={styles.permissionItem}>
              <span className={styles.permissionLabel}>Read</span>
              <AccessLevelSelect
                value={rule.read}
                onChange={(value) => onUpdate(rule.id, { read: value })}
                disabled={readOnly}
                compact
              />
            </div>
            <div className={styles.permissionItem}>
              <span className={styles.permissionLabel}>Create</span>
              <AccessLevelSelect
                value={rule.create}
                onChange={(value) => onUpdate(rule.id, { create: value })}
                disabled={readOnly}
                compact
              />
            </div>
            <div className={styles.permissionItem}>
              <span className={styles.permissionLabel}>Update</span>
              <AccessLevelSelect
                value={rule.update}
                onChange={(value) => onUpdate(rule.id, { update: value })}
                disabled={readOnly}
                compact
              />
            </div>
            <div className={styles.permissionItem}>
              <span className={styles.permissionLabel}>Delete</span>
              <AccessLevelSelect
                value={rule.delete}
                onChange={(value) => onUpdate(rule.id, { delete: value })}
                disabled={readOnly}
                compact
              />
            </div>
          </>
        ) : (
          // For UI and RESOURCE, show empty placeholders to maintain grid
          <div style={{ gridColumn: 'span 4' }} />
        )}
      </div>
    </div>
  );
};

// =============================================================================
// ADD RULE FORM
// =============================================================================

interface AddRuleFormProps {
  context: RuleContext;
  availableObjects: CatalogObject[];
  onAdd: (rule: AccessRuleCreate) => void;
  onCancel: () => void;
}

const AddRuleForm: React.FC<AddRuleFormProps> = ({ context, availableObjects, onAdd, onCancel }) => {
  const [item, setItem] = useState('');
  const [useCustom, setUseCustom] = useState(false);
  const [view, setView] = useState(true);
  const [read, setRead] = useState<AccessLevel>('n');
  const [create, setCreate] = useState<AccessLevel>('n');
  const [update, setUpdate] = useState<AccessLevel>('n');
  const [del, setDel] = useState<AccessLevel>('n');
  
  // Group objects by feature
  const groupedObjects = useMemo(() => {
    const grouped: Record<string, CatalogObject[]> = {};
    availableObjects.forEach(obj => {
      if (!grouped[obj.featureCode]) {
        grouped[obj.featureCode] = [];
      }
      grouped[obj.featureCode].push(obj);
    });
    return grouped;
  }, [availableObjects]);
  
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    const newRule: AccessRuleCreate = {
      context,
      item: item.trim() || null,
      view,
      ...(context === 'DATA' ? { read, create, update, delete: del } : {}),
    };
    onAdd(newRule);
  };
  
  const getPlaceholder = () => {
    switch (context) {
      case 'DATA':
        return 'z.B. data.feature.trustee.TrusteePosition';
      case 'UI':
        return 'z.B. ui.feature.trustee.dashboard';
      case 'RESOURCE':
        return 'z.B. resource.feature.trustee.documents.create';
    }
  };
  
  const getLabel = (obj: CatalogObject): string => {
    return obj.label.de || obj.label.en || obj.objectKey;
  };
  
  return (
    <form className={styles.addRuleForm} onSubmit={handleSubmit}>
      <div className={styles.formGroup}>
        <div className={styles.objectSelectorLabel}>
          <label className={styles.formLabel}>Objekt auswählen</label>
          <button 
            type="button"
            className={styles.toggleCustomButton}
            onClick={() => setUseCustom(!useCustom)}
          >
            {useCustom ? '← Aus Katalog wählen' : 'Freie Eingabe →'}
          </button>
        </div>
        
        {useCustom ? (
          <input
            type="text"
            value={item}
            onChange={(e) => setItem(e.target.value)}
            placeholder={getPlaceholder()}
            className={styles.formInput}
            autoFocus
          />
        ) : (
          <select
            value={item}
            onChange={(e) => setItem(e.target.value)}
            className={styles.formSelect}
          >
            <option value="">-- Global (alle Objekte) --</option>
            {Object.entries(groupedObjects).map(([feature, objs]) => (
              <optgroup key={feature} label={feature.toUpperCase()}>
                {objs.map(obj => (
                  <option key={obj.objectKey} value={obj.objectKey}>
                    {obj.objectKey} - {getLabel(obj)}
                  </option>
                ))}
              </optgroup>
            ))}
          </select>
        )}
        
        <span className={styles.formHint}>
          Leer lassen für globale Regel. Längster Match gewinnt bei Wildcards (z.B. data.feature.trustee.*).
        </span>
      </div>
      
      <div className={styles.formGroup}>
        <label className={styles.formLabel}>
          <input
            type="checkbox"
            checked={view}
            onChange={(e) => setView(e.target.checked)}
            style={{ marginRight: '0.5rem' }}
          />
          Sichtbar (View)
        </label>
      </div>
      
      {context === 'DATA' && (
        <div className={styles.addRuleMatrix}>
          {/* Header Row */}
          <div className={styles.matrixHeader}>
            <div className={styles.matrixLabel}></div>
            <div className={styles.matrixGroup}>Eigene (m)</div>
            <div className={styles.matrixGroup}>Gruppe (g)</div>
            <div className={styles.matrixGroup}>Alle (a)</div>
          </div>
          
          {/* CRUD Rows */}
          {(['create', 'read', 'update', 'delete'] as const).map(op => {
            const value = op === 'delete' ? del : op === 'create' ? create : op === 'update' ? update : read;
            const setValue = op === 'delete' ? setDel : op === 'create' ? setCreate : op === 'update' ? setUpdate : setRead;
            const labels = { create: 'Create', read: 'Read', update: 'Update', delete: 'Delete' };
            
            return (
              <div key={op} className={styles.matrixRow}>
                <div className={styles.matrixLabel}>{labels[op]}</div>
                {(['m', 'g', 'a'] as const).map(level => (
                  <div key={level} className={styles.matrixCell}>
                    <input
                      type="checkbox"
                      checked={value === level || (level === 'm' && (value === 'g' || value === 'a')) || (level === 'g' && value === 'a')}
                      onChange={(e) => {
                        if (e.target.checked) {
                          setValue(level);
                        } else {
                          // Deactivate: set to level below
                          const hierarchy: AccessLevel[] = ['n', 'm', 'g', 'a'];
                          const idx = hierarchy.indexOf(level);
                          setValue(hierarchy[idx - 1] || 'n');
                        }
                      }}
                      title={`${labels[op]} - ${level === 'm' ? 'Eigene' : level === 'g' ? 'Gruppe' : 'Alle'}`}
                    />
                  </div>
                ))}
              </div>
            );
          })}
        </div>
      )}
      
      <div className={styles.formActions}>
        <button type="button" className={styles.secondaryButton} onClick={onCancel}>
          Abbrechen
        </button>
        <button type="submit" className={styles.primaryButton}>
          <FaPlus /> Hinzufügen
        </button>
      </div>
    </form>
  );
};

// =============================================================================
// RULES SECTION
// =============================================================================

interface RulesSectionProps {
  context: RuleContext;
  rules: AccessRule[];
  availableObjects: CatalogObject[];
  readOnly?: boolean;
  onUpdate: (ruleId: string, updates: Partial<AccessRule>) => void;
  onDelete: (ruleId: string) => void;
  onAdd: (rule: AccessRuleCreate) => void;
}

const RulesSection: React.FC<RulesSectionProps> = ({
  context,
  rules,
  availableObjects,
  readOnly,
  onUpdate,
  onDelete,
  onAdd,
}) => {
  const [showAddForm, setShowAddForm] = useState(false);
  const [useTableView, setUseTableView] = useState(context === 'DATA'); // Default to table for DATA
  
  const handleAdd = (rule: AccessRuleCreate) => {
    onAdd(rule);
    setShowAddForm(false);
  };
  
  const getEmptyIcon = () => {
    switch (context) {
      case 'DATA': return <FaTable />;
      case 'UI': return <FaDesktop />;
      case 'RESOURCE': return <FaServer />;
    }
  };
  
  const getEmptyText = () => {
    switch (context) {
      case 'DATA': return 'Keine Daten-Regeln definiert';
      case 'UI': return 'Keine UI-Regeln definiert';
      case 'RESOURCE': return 'Keine Ressourcen-Regeln definiert';
    }
  };
  
  return (
    <div className={styles.rulesSection}>
      {!readOnly && !showAddForm && (
        <div className={styles.sectionHeader}>
          <span className={styles.sectionTitle}>
            {rules.length} {rules.length === 1 ? 'Regel' : 'Regeln'}
          </span>
          <div className={styles.headerActions}>
            {/* View Toggle */}
            {context === 'DATA' && rules.length > 0 && (
              <>
                <button
                  className={`${styles.viewToggleButton} ${useTableView ? styles.active : ''}`}
                  onClick={() => setUseTableView(true)}
                  title="Tabellenansicht"
                >
                  <FaThList />
                </button>
                <button
                  className={`${styles.viewToggleButton} ${!useTableView ? styles.active : ''}`}
                  onClick={() => setUseTableView(false)}
                  title="Kartenansicht"
                >
                  <FaTh />
                </button>
              </>
            )}
            <button
              className={styles.addButton}
              onClick={() => setShowAddForm(true)}
            >
              <FaPlus /> Neue Regel
            </button>
          </div>
        </div>
      )}
      
      {showAddForm && (
        <AddRuleForm
          context={context}
          availableObjects={availableObjects}
          onAdd={handleAdd}
          onCancel={() => setShowAddForm(false)}
        />
      )}
      
      {rules.length === 0 && !showAddForm ? (
        <div className={styles.emptyState}>
          <div className={styles.emptyIcon}>{getEmptyIcon()}</div>
          <p className={styles.emptyText}>{getEmptyText()}</p>
          {!readOnly && (
            <p className={styles.emptyHint}>
              Klicken Sie auf "Neue Regel" um eine Berechtigung hinzuzufügen.
            </p>
          )}
        </div>
      ) : useTableView && context === 'DATA' ? (
        <AccessRulesTable
          rules={rules}
          context={context}
          readOnly={readOnly}
          onUpdate={onUpdate}
          onDelete={onDelete}
        />
      ) : (
        rules.map(rule => (
          <RuleCard
            key={rule.id}
            rule={rule}
            readOnly={readOnly}
            onUpdate={onUpdate}
            onDelete={onDelete}
          />
        ))
      )}
    </div>
  );
};

// =============================================================================
// JSON EDITOR
// =============================================================================

interface JsonEditorProps {
  rules: AccessRule[];
  readOnly?: boolean;
  onApply: (rules: AccessRule[]) => void;
}

const JsonEditor: React.FC<JsonEditorProps> = ({ rules, readOnly, onApply }) => {
  const [jsonText, setJsonText] = useState('');
  const [error, setError] = useState<string | null>(null);
  
  useEffect(() => {
    setJsonText(JSON.stringify(rules, null, 2));
    setError(null);
  }, [rules]);
  
  const handleApply = () => {
    try {
      const parsed = JSON.parse(jsonText);
      if (!Array.isArray(parsed)) {
        throw new Error('JSON muss ein Array sein');
      }
      setError(null);
      onApply(parsed);
    } catch (err: any) {
      setError(err.message);
    }
  };
  
  return (
    <div className={styles.jsonEditor}>
      <textarea
        value={jsonText}
        onChange={(e) => setJsonText(e.target.value)}
        className={styles.jsonTextarea}
        readOnly={readOnly}
        spellCheck={false}
      />
      {error && <div className={styles.jsonError}>{error}</div>}
      <p className={styles.jsonHint}>
        Experten-Modus: Bearbeiten Sie die Regeln direkt als JSON. 
        Änderungen werden erst nach Klick auf "Anwenden" übernommen.
      </p>
      {!readOnly && (
        <div className={styles.formActions}>
          <button
            type="button"
            className={styles.primaryButton}
            onClick={handleApply}
            disabled={!!error}
          >
            JSON anwenden
          </button>
        </div>
      )}
    </div>
  );
};

// =============================================================================
// MAIN COMPONENT
// =============================================================================

export const AccessRulesEditor: React.FC<AccessRulesEditorProps> = ({
  roleId,
  roleName,
  isTemplate = false,
  readOnly = false,
  onSave,
  apiBasePath = '/api/rbac',
  mandateId,
  featureCode,
}) => {
  const { showError } = useToast();
  const {
    rules,
    loading,
    saving,
    error,
    fetchRules,
    saveRules,
    getGroupedRules,
    updateRuleLocally,
    addRuleLocally,
    removeRuleLocally,
  } = useAccessRules(roleId, apiBasePath, mandateId);
  
  // Catalog objects for dropdown selection
  const { objects: catalogObjects, fetchObjects } = useCatalogObjects();
  
  const [activeTab, setActiveTab] = useState<TabType>('DATA');
  const [hasChanges, setHasChanges] = useState(false);
  const [originalRules, setOriginalRules] = useState<AccessRule[]>([]);
  
  // Load rules on mount
  useEffect(() => {
    fetchRules().then(fetchedRules => {
      setOriginalRules(fetchedRules);
    });
  }, [fetchRules]);
  
  // Load catalog objects - filter by featureCode if provided
  useEffect(() => {
    fetchObjects(undefined, featureCode, mandateId);
  }, [fetchObjects, featureCode, mandateId]);
  
  // Get objects for current tab
  const currentContextObjects = useMemo(() => {
    if (activeTab === 'JSON') return [];
    return catalogObjects[activeTab] || [];
  }, [catalogObjects, activeTab]);
  
  // Track changes
  useEffect(() => {
    setHasChanges(JSON.stringify(rules) !== JSON.stringify(originalRules));
  }, [rules, originalRules]);
  
  const groupedRules = getGroupedRules();
  
  // Handlers
  const handleUpdate = useCallback((ruleId: string, updates: Partial<AccessRule>) => {
    updateRuleLocally(ruleId, updates);
  }, [updateRuleLocally]);
  
  const handleDelete = useCallback((ruleId: string) => {
    // Direct delete - rules are local until saved
    removeRuleLocally(ruleId);
  }, [removeRuleLocally]);
  
  const handleAdd = useCallback((ruleData: AccessRuleCreate) => {
    const newRule: AccessRule = {
      id: `temp-${Date.now()}`, // Temporary ID
      roleId,
      context: ruleData.context,
      item: ruleData.item || null,
      view: ruleData.view ?? true,
      read: ruleData.read ?? null,
      create: ruleData.create ?? null,
      update: ruleData.update ?? null,
      delete: ruleData.delete ?? null,
    };
    addRuleLocally(newRule);
  }, [roleId, addRuleLocally]);
  
  const handleSave = async () => {
    const result = await saveRules(rules);
    if (result.success) {
      setOriginalRules(rules);
      setHasChanges(false);
      onSave?.();
    } else {
      showError('Fehler', result.error || 'Fehler beim Speichern');
    }
  };
  
  const handleReset = () => {
    // Direct reset - user clicked the reset button intentionally
    fetchRules().then(fetchedRules => {
      setOriginalRules(fetchedRules);
    });
  };
  
  const handleJsonApply = (newRules: AccessRule[]) => {
    // Replace all rules
    newRules.forEach((rule, index) => {
      if (!rule.id) {
        rule.id = `temp-${Date.now()}-${index}`;
      }
      rule.roleId = roleId;
    });
    // This is a bit hacky - we need to update the store
    // For now, we'll just save directly
    saveRules(newRules);
  };
  
  // Render tabs
  const tabs: { id: TabType; label: string; icon: React.ReactNode; count: number }[] = [
    { id: 'DATA', label: 'Daten', icon: <FaTable />, count: groupedRules.DATA.length },
    { id: 'UI', label: 'UI', icon: <FaDesktop />, count: groupedRules.UI.length },
    { id: 'RESOURCE', label: 'Ressourcen', icon: <FaServer />, count: groupedRules.RESOURCE.length },
    { id: 'JSON', label: 'JSON', icon: <FaCode />, count: rules.length },
  ];
  
  if (loading) {
    return (
      <div className={styles.accessRulesEditor}>
        <div className={styles.loadingContainer}>
          <div className={styles.spinner} />
          <span>Lade Berechtigungen...</span>
        </div>
      </div>
    );
  }
  
  return (
    <div className={styles.accessRulesEditor}>
      <div className={styles.editorHeader}>
        <h3 className={styles.editorTitle}>
          Berechtigungen{roleName ? `: ${roleName}` : ''}
          {isTemplate && <span className={styles.templateBadge}>Template</span>}
        </h3>
        {!readOnly && hasChanges && (
          <div className={styles.headerActions}>
            <button
              className={styles.secondaryButton}
              onClick={handleReset}
              disabled={saving}
            >
              <FaUndo /> Zurücksetzen
            </button>
          </div>
        )}
      </div>
      
      {error && (
        <div className={styles.jsonError}>
          Fehler: {error}
        </div>
      )}
      
      <div className={styles.tabsContainer}>
        <div className={styles.tabList}>
          {tabs.map(tab => (
            <button
              key={tab.id}
              className={`${styles.tab} ${activeTab === tab.id ? styles.active : ''}`}
              onClick={() => setActiveTab(tab.id)}
            >
              <span className={styles.tabIcon}>{tab.icon}</span>
              {tab.label}
              <span className={styles.tabBadge}>{tab.count}</span>
            </button>
          ))}
        </div>
        
        <div className={styles.tabContent}>
          {activeTab === 'DATA' && (
            <RulesSection
              context="DATA"
              rules={groupedRules.DATA}
              availableObjects={catalogObjects.DATA || []}
              readOnly={readOnly}
              onUpdate={handleUpdate}
              onDelete={handleDelete}
              onAdd={handleAdd}
            />
          )}
          {activeTab === 'UI' && (
            <RulesSection
              context="UI"
              rules={groupedRules.UI}
              availableObjects={catalogObjects.UI || []}
              readOnly={readOnly}
              onUpdate={handleUpdate}
              onDelete={handleDelete}
              onAdd={handleAdd}
            />
          )}
          {activeTab === 'RESOURCE' && (
            <RulesSection
              context="RESOURCE"
              rules={groupedRules.RESOURCE}
              availableObjects={catalogObjects.RESOURCE || []}
              readOnly={readOnly}
              onUpdate={handleUpdate}
              onDelete={handleDelete}
              onAdd={handleAdd}
            />
          )}
          {activeTab === 'JSON' && (
            <JsonEditor
              rules={rules}
              readOnly={readOnly}
              onApply={handleJsonApply}
            />
          )}
        </div>
      </div>
      
      {!readOnly && (
        <div className={styles.actionBar}>
          <button
            className={styles.primaryButton}
            onClick={handleSave}
            disabled={saving || !hasChanges}
          >
            {saving ? (
              <>
                <FaSpinner className="spinning" /> Speichern...
              </>
            ) : (
              <>
                <FaSave /> Speichern
              </>
            )}
          </button>
        </div>
      )}
    </div>
  );
};

export default AccessRulesEditor;
