import { useCallback, useEffect, useMemo, useState } from 'react';
import { Button } from 'primereact/button';
import { ProgressSpinner } from 'primereact/progressspinner';
import { api } from '../api/client';

function formatBytes(value) {
  const n = Number(value);
  if (!Number.isFinite(n) || n <= 0) {
    return '';
  }
  const units = ['B', 'KB', 'MB', 'GB', 'TB'];
  let index = 0;
  let current = n;
  while (current >= 1024 && index < units.length - 1) {
    current /= 1024;
    index += 1;
  }
  return `${current.toFixed(index <= 1 ? 0 : 1)} ${units[index]}`;
}

function formatDateTime(value) {
  if (!value) {
    return '-';
  }
  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    return '-';
  }
  return parsed.toLocaleString('de-DE');
}

function getNodeByPath(root, targetPath) {
  if (!root) {
    return null;
  }
  if ((root.path || '') === (targetPath || '')) {
    return root;
  }
  for (const child of (root.children || [])) {
    if (child.type !== 'folder') {
      continue;
    }
    const found = getNodeByPath(child, targetPath);
    if (found) {
      return found;
    }
  }
  return null;
}

function listChildren(node) {
  if (!node || !Array.isArray(node.children)) {
    return [];
  }
  return node.children;
}

function buildBreadcrumb(pathValue) {
  if (!pathValue) {
    return [];
  }
  const parts = String(pathValue).split('/').filter(Boolean);
  return parts.map((part, index) => ({
    name: part,
    path: parts.slice(0, index + 1).join('/')
  }));
}

function filterFolderTree(node, query) {
  if (!node || node.type !== 'folder') {
    return null;
  }
  if (!query || !query.trim()) {
    return node;
  }
  const normalized = query.toLowerCase();
  const children = (node.children || [])
    .filter((child) => child.type === 'folder')
    .map((child) => filterFolderTree(child, query))
    .filter(Boolean);
  const nameMatches = String(node.name || '').toLowerCase().includes(normalized);
  if (nameMatches || children.length > 0) {
    return { ...node, children };
  }
  return null;
}

function defaultExpandedSet(tree) {
  const next = new Set(['']);
  const firstLevel = Array.isArray(tree?.children) ? tree.children : [];
  for (const entry of firstLevel) {
    if (entry?.type === 'folder' && entry?.path) {
      next.add(entry.path);
    }
  }
  return next;
}

export default function AudiobookOutputExplorer({ refreshToken = 0 }) {
  const [tree, setTree] = useState(null);
  const [outputDir, setOutputDir] = useState(null);
  const [loading, setLoading] = useState(false);
  const [errorMessage, setErrorMessage] = useState('');
  const [currentPath, setCurrentPath] = useState('');
  const [expandedFolders, setExpandedFolders] = useState(() => new Set(['']));
  const [sidebarQuery, setSidebarQuery] = useState('');

  const loadTree = useCallback(async () => {
    setLoading(true);
    setErrorMessage('');
    try {
      const response = await api.getAudiobookOutputTree();
      const nextTree = response?.tree || null;
      setTree(nextTree);
      setOutputDir(response?.outputDir || null);
      setExpandedFolders(defaultExpandedSet(nextTree));
      setCurrentPath('');
    } catch (error) {
      setTree(null);
      setErrorMessage(error?.message || 'Explorer konnte nicht geladen werden.');
    } finally {
      setLoading(false);
    }
  }, []);

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

  const navigateTo = (pathValue) => {
    const normalized = String(pathValue || '').trim();
    const node = getNodeByPath(tree, normalized);
    if (node && node.type === 'folder') {
      setCurrentPath(normalized);
    }
  };

  const toggleFolder = (pathValue) => {
    const normalized = String(pathValue || '').trim();
    setExpandedFolders((prev) => {
      const next = new Set(prev);
      if (next.has(normalized)) {
        next.delete(normalized);
      } else {
        next.add(normalized);
      }
      return next;
    });
  };

  const renderTreeNode = (node, depth = 0) => {
    if (!node || node.type !== 'folder') {
      return null;
    }
    const key = node.path || '';
    const isExpanded = expandedFolders.has(key);
    const isCurrent = currentPath === key;
    const children = Array.isArray(node.children) ? node.children.filter((entry) => entry.type === 'folder') : [];

    return (
      <div key={key || '__root__'} className={`tree-node depth-${depth}`}>
        <button
          type="button"
          className={`tree-row folder${isCurrent ? ' active' : ''}`}
          onClick={() => navigateTo(key)}
        >
          {children.length > 0 ? (
            <span
              className="tree-caret"
              onClick={(event) => {
                event.stopPropagation();
                toggleFolder(key);
              }}
            >
              <i className={`pi ${isExpanded ? 'pi-chevron-down' : 'pi-chevron-right'}`} />
            </span>
          ) : (
            <span className="tree-caret disabled" aria-hidden="true" />
          )}
          <span className="tree-icon folder">
            <i className="pi pi-folder" />
          </span>
          <span className="tree-label">{node.name || 'audiobooks'}</span>
        </button>
        {isExpanded && children.map((child) => renderTreeNode(child, depth + 1))}
      </div>
    );
  };

  const filteredTree = useMemo(() => filterFolderTree(tree, sidebarQuery), [tree, sidebarQuery]);
  const currentNode = getNodeByPath(tree, currentPath);
  const currentChildren = listChildren(currentNode);
  const breadcrumb = buildBreadcrumb(currentPath);

  if (loading && !tree) {
    return (
      <div className="explorer-loading">
        <ProgressSpinner style={{ width: '2.2rem', height: '2.2rem' }} strokeWidth="5" />
      </div>
    );
  }

  if (!tree) {
    return (
      <div className="explorer-empty">
        {errorMessage ? (
          <small className="error-text">{errorMessage}</small>
        ) : (
          <small>Kein Audiobook-Output vorhanden. Ausgabepfad: <code>{outputDir || 'nicht konfiguriert'}</code></small>
        )}
        <div style={{ marginTop: '0.6rem' }}>
          <Button icon="pi pi-refresh" label="Neu laden" outlined size="small" onClick={() => void loadTree()} />
        </div>
      </div>
    );
  }

  return (
    <div className="explorer audiobook-output-explorer">
      <div className="explorer-sidebar">
        <div className="explorer-toolbar sidebar-toolbar">
          <input
            type="text"
            placeholder="Ordner filtern..."
            value={sidebarQuery}
            onChange={(event) => setSidebarQuery(event.target.value)}
            className="sidebar-search"
          />
        </div>
        <div className="sidebar-tree">
          {filteredTree ? renderTreeNode(filteredTree, 0) : <small>Keine Ordner gefunden.</small>}
        </div>
      </div>

      <div className="explorer-main">
        <div className="explorer-toolbar">
          <Button
            icon={loading ? 'pi pi-spin pi-spinner' : 'pi pi-refresh'}
            label="Aktualisieren"
            outlined
            size="small"
            onClick={() => void loadTree()}
            disabled={loading}
          />
          <div className="explorer-path">
            <Button text label="/" onClick={() => navigateTo('')} />
            {breadcrumb.map((crumb) => (
              <Button key={crumb.path} text label={crumb.name} onClick={() => navigateTo(crumb.path)} />
            ))}
          </div>
        </div>

        <div className="explorer-list">
          <div className="explorer-row header audiobook-output-row">
            <span>Name</span>
            <span>Größe</span>
            <span>Geändert</span>
          </div>

          {currentChildren.length === 0 ? (
            <div className="explorer-row audiobook-output-row">
              <span>Keine Einträge in diesem Ordner.</span>
              <span />
              <span />
            </div>
          ) : (
            currentChildren.map((entry) => (
              <button
                type="button"
                key={entry.path || entry.name}
                className="explorer-row audiobook-output-row"
                onClick={() => {
                  if (entry.type === 'folder') {
                    navigateTo(entry.path);
                  }
                }}
                style={{ cursor: entry.type === 'folder' ? 'pointer' : 'default' }}
              >
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: '0.5rem' }}>
                  <i className={`pi ${entry.type === 'folder' ? 'pi-folder' : 'pi-file'}`} />
                  {entry.name}
                </span>
                <span>{entry.type === 'file' ? (formatBytes(entry.size) || '-') : '-'}</span>
                <span>{formatDateTime(entry.mtime)}</span>
              </button>
            ))
          )}
        </div>

        <div className="explorer-footer">
          <small>
            Root: <code>{outputDir || '-'}</code>
          </small>
        </div>
      </div>
    </div>
  );
}
