import React, { useState, useEffect, useMemo } from 'react';
import { Form, Badge, Button, Spinner } from 'react-bootstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronRight, faSearch, faTimes, faFilter, faCheck } from '@fortawesome/free-solid-svg-icons';
import { getResources, getResourceTags } from '../services/authorizationService';
import MultiSelectDropdown from '../../../globalComponents/form/dropdowns/MultiSelectDropdown';

/**
 * ScopeSelector
 * Props:
 *   dimensions: string[]   - ordered list of dimension keys (contextual)
 *   structuralRoot: string - root resource type name (structural)
 *   resourceTypeMap: {}    - name => ResourceTypeEntity
 *   onScopeChange: (scope) => void
 *   initialScope: {}
 */
const ScopeSelector = ({ dimensions, structuralRoot, resourceTypeMap, onScopeChange, initialScope = {} }) => {
  const isContextual = !!dimensions?.length;
  const isStructural = !!structuralRoot;

  // Contextual: track selected per dimension
  const [contextSelections, setContextSelections] = useState(initialScope || {});
  // Structural: track breadcrumb path [{type, resource}]
  const [structuralPath, setStructuralPath] = useState([]);
  const [leafSelections, setLeafSelections] = useState(initialScope?.leafIds || []);

  // Resources loaded per level
  const [resourcesByLevel, setResourcesByLevel] = useState({});
  const [loadingLevel, setLoadingLevel] = useState(null);
  const [searchTerms, setSearchTerms] = useState({});
  const [tagFilters, setTagFilters] = useState({});
  const [availableTags, setAvailableTags] = useState({});

  // ---- Structural chain ----
  const structuralChain = useMemo(() => {
    if (!isStructural || !resourceTypeMap) return [];
    const chain = [];
    let current = resourceTypeMap[structuralRoot];
    while (current) {
      chain.push(current);
      const child = Object.values(resourceTypeMap).find(
        rt => rt.parentTypeId === current.id && rt.relationType === 'STRUCTURAL'
      );
      current = child;
    }
    return chain;
  }, [structuralRoot, resourceTypeMap, isStructural]);

  // Load resources for structural level
  const loadStructuralLevel = async (typeName, parentResourceId = null, levelIdx = 0) => {
    setLoadingLevel(levelIdx);
    try {
      const resources = await getResources(typeName, parentResourceId);
      const tags = await getResourceTags(typeName).catch(() => ({}));
      setResourcesByLevel(prev => ({ ...prev, [levelIdx]: resources }));
      setAvailableTags(prev => ({ ...prev, [typeName]: tags }));
    } finally {
      setLoadingLevel(null);
    }
  };

  // Load resources for contextual dimension
  const loadContextualLevel = async (dimName, parentId = null) => {
    setLoadingLevel(dimName);
    try {
      const resources = await getResources(dimName, parentId);
      const tags = await getResourceTags(dimName).catch(() => ({}));
      setResourcesByLevel(prev => ({ ...prev, [dimName]: resources }));
      setAvailableTags(prev => ({ ...prev, [dimName]: tags }));
    } finally {
      setLoadingLevel(null);
    }
  };

  // Init
  useEffect(() => {
    if (isStructural && structuralChain.length > 0) {
      loadStructuralLevel(structuralChain[0].name, null, 0);
    }
    if (isContextual && dimensions.length > 0) {
      loadContextualLevel(dimensions[0]);
    }
  }, [isStructural, isContextual]);

  // ---- Structural handlers ----
  const handleStructuralSelect = (resource, levelIdx) => {
    const newPath = structuralPath.slice(0, levelIdx);
    newPath.push({ type: structuralChain[levelIdx].name, resource });
    setStructuralPath(newPath);
    setLeafSelections([]);

    const nextLevel = levelIdx + 1;
    if (nextLevel < structuralChain.length) {
      // Clear deeper levels
      const newResources = {};
      Object.keys(resourcesByLevel).forEach(k => {
        if (Number(k) <= levelIdx) newResources[k] = resourcesByLevel[k];
      });
      setResourcesByLevel(newResources);
      loadStructuralLevel(structuralChain[nextLevel].name, resource.id, nextLevel);
    } else {
      // Leaf — emit scope
      const scope = {};
      newPath.forEach(p => { scope[p.type] = p.resource.resourcePk; });
      onScopeChange?.(scope);
    }
  };

  const handleLeafToggle = (resource) => {
    const newSel = leafSelections.includes(resource.id)
      ? leafSelections.filter(id => id !== resource.id)
      : [...leafSelections, resource.id];
    setLeafSelections(newSel);

    const scope = {};
    structuralPath.forEach(p => { scope[p.type] = p.resource.resourcePk; });
    scope[structuralChain[structuralChain.length - 1].name] = newSel;
    onScopeChange?.(scope);
  };

  // ---- Contextual handlers ----
  const handleContextualSelect = (dimName, resource, dimIdx) => {
    const nextIdx = dimIdx + 1;
    const newSelections = { ...contextSelections, [dimName]: resource };

    // Clear downstream
    dimensions.slice(nextIdx).forEach(d => delete newSelections[d]);
    setContextSelections(newSelections);

    if (nextIdx < dimensions.length) {
      loadContextualLevel(dimensions[nextIdx], resource.id);
    } else {
      const scope = {};
      Object.entries(newSelections).forEach(([k, v]) => {
        scope[k] = Array.isArray(v) ? v.map(r => r.resourcePk) : v.resourcePk;
      });
      onScopeChange?.(scope);
    }
  };

  const handleContextualMultiToggle = (dimName, resource) => {
    const current = Array.isArray(contextSelections[dimName]) ? contextSelections[dimName] : [];
    const exists = current.find(r => r.id === resource.id);
    const updated = exists ? current.filter(r => r.id !== resource.id) : [...current, resource];
    const newSelections = { ...contextSelections, [dimName]: updated };
    setContextSelections(newSelections);

    const scope = {};
    dimensions.forEach((dim, idx) => {
      const sel = newSelections[dim];
      if (!sel) return;
      if (idx === dimensions.length - 1) {
        scope[dim] = Array.isArray(sel) ? sel.map(r => r.resourcePk) : [sel.resourcePk];
      } else {
        scope[dim] = Array.isArray(sel) ? sel[0]?.resourcePk : sel.resourcePk;
      }
    });
    onScopeChange?.(scope);
  };

  // Filter resources by search + tags
  const getFilteredResources = (levelKey, typeName) => {
    const resources = resourcesByLevel[levelKey] || [];
    const search = (searchTerms[levelKey] || '').toLowerCase();
    const filters = tagFilters[typeName] || {};

    return resources.filter(r => {
      if (search && !r.displayName.toLowerCase().includes(search)) return false;
      for (const [tagKey, tagVal] of Object.entries(filters)) {
        if (tagVal && r.tags?.[tagKey] !== tagVal) return false;
      }
      return true;
    });
  };

  const renderTagFilters = (typeName, levelKey) => {
    const tags = availableTags[typeName] || {};
    if (Object.keys(tags).length === 0) return null;
    return (
      <div className="scope-tag-filters">
        {Object.entries(tags).map(([tagKey, tagVals]) => (
          <Form.Select
            key={tagKey}
            size="sm"
            className="scope-tag-select"
            value={tagFilters[typeName]?.[tagKey] || ''}
            onChange={e => setTagFilters(prev => ({
              ...prev,
              [typeName]: { ...(prev[typeName] || {}), [tagKey]: e.target.value }
            }))}
          >
            <option value="">{tagKey}: All</option>
            {(Array.isArray(tagVals) ? tagVals : []).map(v => (
              <option key={v} value={v}>{v}</option>
            ))}
          </Form.Select>
        ))}
      </div>
    );
  };

  const renderResourceList = (levelKey, typeName, onSelect, selectedId, isMulti = false, selectedIds = []) => {
    const filtered = getFilteredResources(levelKey, typeName);

    if (isMulti) {
      const options = filtered.map(r => ({ value: r.id, label: r.displayName }));
      return (
        <div className="scope-level-panel">
          <div className="scope-level-header">
            <span className="scope-level-title">{typeName}</span>
            {selectedIds.length > 0 && (
              <Badge bg="primary" className="scope-count-badge">{selectedIds.length} selected</Badge>
            )}
          </div>
          <div style={{ padding: "10px 14px 160px" }}>
            <MultiSelectDropdown
              options={options}
              selected={selectedIds}
              onChange={(newIds) => {
                const added = newIds.filter(id => !selectedIds.includes(id));
                const removed = selectedIds.filter(id => !newIds.includes(id));
                const changedId = added.length > 0 ? added[0] : removed[0];
                if (changedId !== undefined) {
                  const targetRes = (resourcesByLevel[levelKey] || []).find(r => r.id === changedId);
                  if (targetRes) onSelect(targetRes);
                }
              }}
              placeholder={`Select ${typeName}...`}
            />
          </div>
        </div>
      );
    }

    return (
      <div className="scope-level-panel">
        <div className="scope-level-header">
          <span className="scope-level-title">{typeName}</span>
          {isMulti && selectedIds.length > 0 && (
            <Badge bg="primary" className="scope-count-badge">{selectedIds.length} selected</Badge>
          )}
        </div>
        <div className="scope-search-row">
          <div className="scope-search-input">
            <FontAwesomeIcon icon={faSearch} className="scope-search-icon" />
            <input
              type="text"
              placeholder={`Search ${typeName}...`}
              value={searchTerms[levelKey] || ''}
              onChange={e => setSearchTerms(prev => ({ ...prev, [levelKey]: e.target.value }))}
            />
          </div>
          {renderTagFilters(typeName, typeName)}
        </div>
        <div className="scope-resource-list">
          {loadingLevel === levelKey || loadingLevel === typeName ? (
            <div className="scope-loading"><Spinner size="sm" /> Loading...</div>
          ) : filtered.length === 0 ? (
            <div className="scope-empty">No resources found</div>
          ) : (
            filtered.map(resource => {
              const isSelected = isMulti
                ? selectedIds.includes(resource.id)
                : selectedId === resource.id;
              return (
                <div
                  key={resource.id}
                  className={`scope-resource-item ${isSelected ? 'selected' : ''}`}
                  onClick={() => onSelect(resource)}
                >
                  <span className="resource-name">{resource.displayName}</span>
                  {isSelected && (
                    <FontAwesomeIcon icon={isMulti ? faCheck : faChevronRight} className="resource-check" />
                  )}
                  {!isSelected && !isMulti && (
                    <FontAwesomeIcon icon={faChevronRight} className="resource-arrow" />
                  )}
                </div>
              );
            })
          )}
        </div>
      </div>
    );
  };

  if (isStructural) {
    return (
      <div className="scope-selector">
        <div className="scope-panels-row">
          {structuralChain.map((rt, idx) => {
            if (idx > structuralPath.length) return null;
            const isLeaf = idx === structuralChain.length - 1;
            const selectedResource = structuralPath[idx]?.resource;

            if (isLeaf) {
              return renderResourceList(
                idx, rt.name,
                (r) => handleLeafToggle(r),
                null, true, leafSelections
              );
            }

            return renderResourceList(
              idx, rt.name,
              (r) => handleStructuralSelect(r, idx),
              selectedResource?.id
            );
          })}
        </div>
      </div>
    );
  }

  if (isContextual) {
    return (
      <div className="scope-selector">
        <div className="scope-panels-row">
          {dimensions.map((dim, idx) => {
            // Only show if previous dim is selected (or it's the first)
            if (idx > 0 && !contextSelections[dimensions[idx - 1]]) return null;
            const isLast = idx === dimensions.length - 1;
            const selected = contextSelections[dim];
            const selectedIds = isLast && Array.isArray(selected) ? selected.map(r => r.id) : [];
            const selectedId = !isLast ? selected?.id : null;

            return renderResourceList(
              dim, dim,
              (r) => isLast
                ? handleContextualMultiToggle(dim, r)
                : handleContextualSelect(dim, r, idx),
              selectedId,
              isLast,
              selectedIds
            );
          })}
        </div>
      </div>
    );
  }

  return (
    <div className="scope-selector-empty">
      <p className="text-muted">No dimensions required for this capability.</p>
    </div>
  );
};

export default ScopeSelector;