<script lang="ts">
  import type { GitFile, GitRepoInfo } from '../../services/content/git-repo-fetcher.js';
  import { fetchGitHubApi } from '../../services/github-api.js';
  import { browser } from '$app/environment';
  // @ts-ignore - highlight.js default export works at runtime
  import hljs from 'highlight.js';
  import 'highlight.js/styles/vs2015.css';
  import Icon from '../ui/Icon.svelte';

  interface Props {
    files: GitFile[];
    repoInfo: GitRepoInfo;
  }

  let { files, repoInfo }: Props = $props();

  // Track expanded folders
  let expandedPaths = $state<Set<string>>(new Set());
  
  // Track selected file and its content
  let selectedFile = $state<GitFile | null>(null);
  let fileContent = $state<string | null>(null);
  let loadingContent = $state(false);
  let contentError = $state<string | null>(null);
  let codeRef = $state<HTMLElement | null>(null);
  let fileUrl = $state<string | null>(null); // For images and media files

  // Build tree structure
  function buildTree(files: GitFile[]): any {
    const tree: any = {};
    
    for (const file of files) {
      const parts = file.path.split('/').filter(p => p);
      let current = tree;
      
      for (let i = 0; i < parts.length; i++) {
        const part = parts[i];
        const isLast = i === parts.length - 1;
        const isDirectory = file.type === 'dir';
        
        if (isLast) {
          // Last part of path
          if (isDirectory) {
            // Directory - ensure it's an object (not a file)
            if (!current[part] || (current[part].path && !current[part]._isDir)) {
              current[part] = {};
            }
            // Mark as directory
            current[part]._isDir = true;
            current[part]._path = file.path;
          } else {
            // File - store the GitFile object
            // Only overwrite if current entry is a directory placeholder without children
            if (!current[part] || (current[part]._isDir && Object.keys(current[part]).length <= 2)) {
              current[part] = file;
            }
          }
        } else {
          // Intermediate path segment - must be a directory
          if (!current[part]) {
            current[part] = {};
          } else if (current[part].path && !current[part]._isDir) {
            // This was stored as a file, but we need it as a directory
            // This shouldn't happen, but convert it
            const existingFile = current[part];
            current[part] = {};
            current[part][existingFile.name] = existingFile;
          }
          current = current[part];
        }
      }
    }
    
    return tree;
  }

  const fileTree = $derived.by(() => buildTree(files));

  function toggleFolder(path: string) {
    if (expandedPaths.has(path)) {
      expandedPaths.delete(path);
    } else {
      expandedPaths.add(path);
    }
    expandedPaths = new Set(expandedPaths); // Trigger reactivity
  }

  function isExpanded(path: string): boolean {
    return expandedPaths.has(path);
  }

  async function fetchFileContent(file: GitFile) {
    if (selectedFile?.path === file.path && (fileContent || fileUrl)) {
      return; // Already loaded
    }

    selectedFile = file;
    loadingContent = true;
    contentError = null;
    fileContent = null;
    fileUrl = null;

    // For images and media files, we just need the URL, not the content
    if (isImageFile(file) || isVideoFile(file) || isAudioFile(file)) {
      fileUrl = getRawFileUrl(file);
      loadingContent = false;
      return;
    }

    try {
      // Parse the repo URL to determine platform
      const url = repoInfo.url;
      let apiUrl = '';

      if (url.includes('github.com')) {
        // GitHub API: GET /repos/{owner}/{repo}/contents/{path}
        const match = url.match(/github\.com\/([^/]+)\/([^/]+)/);
        if (match) {
          const [, owner, repo] = match;
          apiUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${file.path}?ref=${repoInfo.defaultBranch}`;
        }
      } else if (url.includes('gitlab')) {
        // GitLab API (both gitlab.com and self-hosted): GET /projects/{id}/repository/files/{path}/raw
        const match = url.match(/(https?:\/\/[^/]*gitlab[^/]*)\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
        if (match) {
          const [, baseHost, owner, repo] = match;
          const cleanRepo = repo.replace(/\.git$/, '');
          const projectPath = encodeURIComponent(`${owner}/${cleanRepo}`);
          const apiBase = baseHost.includes('gitlab.com') 
            ? 'https://gitlab.com/api/v4'
            : `${baseHost}/api/v4`;
          // Use proxy endpoint to avoid CORS issues
          // Pass file path with actual slashes - proxy will handle encoding correctly
          apiUrl = `/api/gitea-proxy/projects/${projectPath}/repository/files/${file.path}/raw?baseUrl=${encodeURIComponent(apiBase)}&ref=${repoInfo.defaultBranch}`;
        }
      } else if (url.includes('onedev')) {
        // OneDev API: similar to Gitea, uses /api/v1/repos/{owner}/{repo}/contents/{path}
        const match = url.match(/(https?:\/\/[^/]*onedev[^/]*)\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
        if (match) {
          const [, baseUrl, owner, repo] = match;
          const cleanRepo = repo.replace(/\.git$/, '');
          const baseApiUrl = `${baseUrl}/api/v1`;
          // Use proxy endpoint to avoid CORS issues
          apiUrl = `/api/gitea-proxy/repos/${owner}/${cleanRepo}/contents/${file.path}?baseUrl=${encodeURIComponent(baseApiUrl)}&ref=${repoInfo.defaultBranch}`;
        }
      } else {
        // Try Gitea/Forgejo pattern (handles .git suffix) - generic fallback
        const match = url.match(/(https?:\/\/[^/]+)\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
        if (match) {
          const [, baseUrl, owner, repo] = match;
          const cleanRepo = repo.replace(/\.git$/, '');
          const baseApiUrl = `${baseUrl}/api/v1`;
          // Use proxy endpoint to avoid CORS issues
          apiUrl = `/api/gitea-proxy/repos/${owner}/${cleanRepo}/contents/${file.path}?baseUrl=${encodeURIComponent(baseApiUrl)}&ref=${repoInfo.defaultBranch}`;
        }
      }

      if (!apiUrl) {
        throw new Error('Unable to determine API endpoint for this repository');
      }

      // Use GitHub API helper for GitHub repos (handles rate limiting and token fallback)
      let response: Response;
      if (url.includes('github.com')) {
        const apiResult = await fetchGitHubApi(apiUrl);
        response = apiResult.response;
      } else {
        response = await fetch(apiUrl);
      }
      
      if (!response.ok) {
        throw new Error(`Failed to fetch file: ${response.status} ${response.statusText}`);
      }

      // Check content type to determine how to parse the response
      const contentType = response.headers.get('content-type') || '';
      
      if (url.includes('github.com')) {
        // GitHub API returns JSON with base64 encoded content
        const data = await response.json();
        if (data.content) {
          fileContent = atob(data.content.replace(/\s/g, ''));
        }
      } else if (url.includes('gitlab') && apiUrl.includes('/raw')) {
        // GitLab raw file endpoint returns plain text
        fileContent = await response.text();
      } else if (contentType.includes('application/json')) {
        // Other platforms that return JSON (like Gitea contents API)
        const data = await response.json();
        if (data.content) {
          // Some APIs return base64 content in JSON
          fileContent = atob(data.content.replace(/\s/g, ''));
        } else if (typeof data === 'string') {
          fileContent = data;
        }
      } else {
        // Default to text for raw file endpoints
        fileContent = await response.text();
      }
    } catch (error) {
      console.error('Error fetching file content:', error);
      contentError = error instanceof Error ? error.message : 'Failed to load file content';
    } finally {
      loadingContent = false;
    }
  }

  function getFileIconName(file: GitFile): string {
    const ext = file.name.split('.').pop()?.toLowerCase() || '';
    const iconMap: Record<string, string> = {
      // Code files
      'js': 'code', 'ts': 'code', 'jsx': 'code', 'tsx': 'code',
      'py': 'code', 'java': 'code', 'cpp': 'code', 'c': 'code',
      'html': 'code', 'css': 'code', 'scss': 'code', 'sass': 'code',
      'rs': 'code', 'go': 'code', 'php': 'code', 'rb': 'code',
      'sh': 'code', 'bash': 'code', 'zsh': 'code',
      // Data/config files
      'json': 'file-text', 'yaml': 'file-text', 'yml': 'file-text', 'toml': 'file-text',
      // Text files
      'md': 'file-text', 'txt': 'file-text', 'adoc': 'file-text',
      // Images
      'png': 'image', 'jpg': 'image', 'jpeg': 'image', 'gif': 'image', 'svg': 'image',
      // Other files
      'pdf': 'file-text', 'zip': 'file-text', 'tar': 'file-text', 'gz': 'file-text'
    };
    return iconMap[ext] || 'file-text';
  }

  function formatFileSize(bytes?: number): string {
    if (!bytes) return '';
    if (bytes < 1024) return `${bytes} B`;
    if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
  }

  function getFileExtension(file: GitFile): string {
    const parts = file.name.split('.');
    return parts.length > 1 ? parts[parts.length - 1].toLowerCase() : '';
  }

  function isImageFile(file: GitFile): boolean {
    const ext = getFileExtension(file);
    return ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'bmp', 'ico'].includes(ext);
  }

  function isVideoFile(file: GitFile): boolean {
    const ext = getFileExtension(file);
    return ['mp4', 'webm', 'ogg', 'mov', 'avi', 'mkv', 'wmv', 'flv'].includes(ext);
  }

  function isAudioFile(file: GitFile): boolean {
    const ext = getFileExtension(file);
    return ['mp3', 'wav', 'ogg', 'oga', 'aac', 'm4a', 'flac', 'wma'].includes(ext);
  }

  function isCodeFile(file: GitFile): boolean {
    const ext = getFileExtension(file);
    const codeExtensions = [
      'js', 'ts', 'jsx', 'tsx', 'py', 'java', 'cpp', 'c', 'h', 'hpp',
      'html', 'css', 'scss', 'sass', 'less', 'json', 'yaml', 'yml',
      'xml', 'md', 'txt', 'sh', 'bash', 'zsh', 'rs', 'go', 'php', 'rb',
      'swift', 'kt', 'dart', 'vue', 'svelte', 'r', 'sql', 'pl', 'lua',
      'clj', 'hs', 'elm', 'ex', 'exs', 'ml', 'fs', 'vb', 'cs', 'd',
      'pas', 'ada', 'erl', 'hrl', 'vim', 'vimrc', 'zshrc', 'bashrc',
      'dockerfile', 'makefile', 'cmake', 'gradle', 'maven', 'pom',
      'toml', 'ini', 'conf', 'config', 'properties', 'env', 'gitignore',
      'dockerignore', 'editorconfig', 'eslintrc', 'prettierrc'
    ];
    return codeExtensions.includes(ext);
  }

  function getLanguageFromExtension(file: GitFile): string {
    const ext = getFileExtension(file);
    const languageMap: Record<string, string> = {
      'js': 'javascript', 'ts': 'typescript', 'jsx': 'javascript', 'tsx': 'typescript',
      'py': 'python', 'java': 'java', 'cpp': 'cpp', 'c': 'c', 'h': 'c', 'hpp': 'cpp',
      'html': 'html', 'css': 'css', 'scss': 'scss', 'sass': 'sass', 'less': 'less',
      'json': 'json', 'yaml': 'yaml', 'yml': 'yaml', 'xml': 'xml',
      'md': 'markdown', 'txt': 'plaintext', 'sh': 'bash', 'bash': 'bash', 'zsh': 'bash',
      'rs': 'rust', 'go': 'go', 'php': 'php', 'rb': 'ruby',
      'swift': 'swift', 'kt': 'kotlin', 'dart': 'dart', 'vue': 'vue', 'svelte': 'svelte',
      'r': 'r', 'sql': 'sql', 'pl': 'perl', 'lua': 'lua',
      'clj': 'clojure', 'hs': 'haskell', 'elm': 'elm', 'ex': 'elixir', 'exs': 'elixir',
      'ml': 'ocaml', 'fs': 'fsharp', 'vb': 'vbnet', 'cs': 'csharp', 'd': 'd',
      'pas': 'pascal', 'ada': 'ada', 'erl': 'erlang', 'hrl': 'erlang',
      'vim': 'vim', 'vimrc': 'vim', 'zshrc': 'bash', 'bashrc': 'bash',
      'dockerfile': 'dockerfile', 'makefile': 'makefile', 'cmake': 'cmake',
      'gradle': 'gradle', 'maven': 'xml', 'pom': 'xml',
      'toml': 'toml', 'ini': 'ini', 'conf': 'ini', 'config': 'ini',
      'properties': 'properties', 'env': 'bash', 'gitignore': 'plaintext',
      'dockerignore': 'plaintext', 'editorconfig': 'ini', 'eslintrc': 'json', 'prettierrc': 'json'
    };
    return languageMap[ext] || 'plaintext';
  }

  function getRawFileUrl(file: GitFile): string {
    const url = repoInfo.url;
    const branch = repoInfo.defaultBranch;
    
    if (url.includes('github.com')) {
      const match = url.match(/github\.com\/([^/]+)\/([^/]+)/);
      if (match) {
        const [, owner, repo] = match;
        return `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${file.path}`;
      }
    } else if (url.includes('gitlab.com')) {
      const match = url.match(/gitlab\.com\/([^/]+)\/([^/]+)/);
      if (match) {
        const [, owner, repo] = match;
        const projectPath = encodeURIComponent(`${owner}/${repo}`);
        return `https://gitlab.com/${owner}/${repo}/-/raw/${branch}/${file.path}`;
      }
    } else {
      // Try Gitea pattern
      const match = url.match(/(https?:\/\/[^/]+)\/([^/]+)\/([^/]+)/);
      if (match) {
        const [, baseUrl, owner, repo] = match;
        return `${baseUrl}/${owner}/${repo}/raw/branch/${branch}/${file.path}`;
      }
    }
    
    return '';
  }

  // Apply syntax highlighting when file content changes
  $effect(() => {
    if (!browser || !hljs) return; // Only run in browser and if hljs is available
    if (fileContent && selectedFile && isCodeFile(selectedFile) && codeRef) {
      const language = getLanguageFromExtension(selectedFile);
      try {
        // Check if language is supported, fallback to plaintext if not
        if (hljs.getLanguage && hljs.getLanguage(language)) {
          codeRef.innerHTML = hljs.highlight(fileContent, { language }).value;
          codeRef.className = `hljs language-${language}`;
        } else {
          // Language not supported, use plaintext
          codeRef.innerHTML = hljs.highlight(fileContent, { language: 'plaintext' }).value;
          codeRef.className = 'hljs language-plaintext';
        }
      } catch (error) {
        // If highlighting fails, just display plain text
        console.warn(`Failed to highlight code with language '${language}':`, error);
        codeRef.textContent = fileContent;
        codeRef.className = 'hljs language-plaintext';
      }
    }
  });
</script>

<div class="file-explorer">
  <div class="file-tree-panel">
    <div class="file-tree-header">
      <h3 class="file-tree-title">Files</h3>
      <button 
        onclick={() => {
          // Expand all
          const allPaths = new Set<string>();
          function collectPaths(tree: any, path: string = '') {
            for (const [name, value] of Object.entries(tree)) {
              if (value && typeof value === 'object' && !('path' in value)) {
                const newPath = path ? `${path}/${name}` : name;
                allPaths.add(newPath);
                collectPaths(value, newPath);
              }
            }
          }
          collectPaths(fileTree);
          expandedPaths = allPaths;
        }}
        class="expand-all-btn"
      >
        Expand All
      </button>
      <button 
        onclick={() => {
          expandedPaths = new Set();
        }}
        class="collapse-all-btn"
      >
        Collapse All
      </button>
    </div>
    <div class="file-tree-content">
      {#each Object.entries(fileTree) as [name, value]}
        {@const isFile = value && typeof value === 'object' && 'path' in value}
        {@const isDir = value && typeof value === 'object' && !('path' in value)}
        {#if isDir}
          {@const dirPath = name}
          {@const isExpandedDir = isExpanded(dirPath)}
          <div class="tree-item tree-folder">
            <button 
              onclick={() => toggleFolder(dirPath)}
              class="tree-folder-btn"
              aria-expanded={isExpandedDir}
            >
              <span class="tree-icon">{isExpandedDir ? '📂' : '📁'}</span>
              <span class="tree-name">{name}</span>
            </button>
            {#if isExpandedDir}
              <div class="tree-children">
                {#each Object.entries(value).sort(([a, valA], [b, valB]) => {
                  const aIsFile = valA && typeof valA === 'object' && 'path' in valA;
                  const bIsFile = valB && typeof valB === 'object' && 'path' in valB;
                  const aIsDir = valA && typeof valA === 'object' && !('path' in valA);
                  const bIsDir = valB && typeof valB === 'object' && !('path' in valB);
                  if (aIsDir && !bIsDir) return -1;
                  if (!aIsDir && bIsDir) return 1;
                  return a.localeCompare(b);
                }) as [subName, subValue]}
                  {#if subValue && typeof subValue === 'object' && 'path' in subValue}
                    {@const file = subValue as GitFile}
                    <div class="tree-item tree-file" class:selected={selectedFile?.path === file.path}>
                      <button 
                        onclick={() => fetchFileContent(file)}
                        class="tree-file-btn"
                      >
                        <span class="tree-icon"><Icon name={getFileIconName(file)} size={16} /></span>
                        <span class="tree-name">{subName}</span>
                        {#if file.size}
                          <span class="tree-size">{formatFileSize(file.size)}</span>
                        {/if}
                      </button>
                    </div>
                  {:else if subValue && typeof subValue === 'object'}
                    {@const subDirPath = `${dirPath}/${subName}`}
                    {@const isExpandedSubDir = isExpanded(subDirPath)}
                    <div class="tree-item tree-folder tree-nested">
                      <button 
                        onclick={() => toggleFolder(subDirPath)}
                        class="tree-folder-btn"
                        aria-expanded={isExpandedSubDir}
                      >
                        <span class="tree-icon">{isExpandedSubDir ? '📂' : '📁'}</span>
                        <span class="tree-name">{subName}</span>
                      </button>
                      {#if isExpandedSubDir}
                        <div class="tree-children">
                          <!-- Recursive rendering for nested folders -->
                          {#each Object.entries(subValue).sort(([a, valA], [b, valB]) => {
                            const aIsFile = valA && typeof valA === 'object' && 'path' in valA;
                            const bIsFile = valB && typeof valB === 'object' && 'path' in valB;
                            const aIsDir = valA && typeof valA === 'object' && !('path' in valA);
                            const bIsDir = valB && typeof valB === 'object' && !('path' in valB);
                            if (aIsDir && !bIsDir) return -1;
                            if (!aIsDir && bIsDir) return 1;
                            return a.localeCompare(b);
                          }) as [nestedName, nestedValue]}
                            {#if nestedValue && typeof nestedValue === 'object' && 'path' in nestedValue}
                              {@const nestedFile = nestedValue as GitFile}
                              <div class="tree-item tree-file" class:selected={selectedFile?.path === nestedFile.path}>
                                <button 
                                  onclick={() => fetchFileContent(nestedFile)}
                                  class="tree-file-btn"
                                >
                                  <span class="tree-icon"><Icon name={getFileIconName(nestedFile)} size={16} /></span>
                                  <span class="tree-name">{nestedName}</span>
                                  {#if nestedFile.size}
                                    <span class="tree-size">{formatFileSize(nestedFile.size)}</span>
                                  {/if}
                                </button>
                              </div>
                            {:else if nestedValue && typeof nestedValue === 'object'}
                              {@const deeperDirPath = `${subDirPath}/${nestedName}`}
                              {@const isExpandedDeeper = isExpanded(deeperDirPath)}
                              <div class="tree-item tree-folder tree-nested">
                                <button 
                                  onclick={() => toggleFolder(deeperDirPath)}
                                  class="tree-folder-btn"
                                  aria-expanded={isExpandedDeeper}
                                >
                                  <span class="tree-icon">{isExpandedDeeper ? '📂' : '📁'}</span>
                                  <span class="tree-name">{nestedName}</span>
                                </button>
                                {#if isExpandedDeeper}
                                  <div class="tree-children">
                                    {#each Object.entries(nestedValue).sort(([a, valA], [b, valB]) => {
                                      const aIsFile = valA && typeof valA === 'object' && 'path' in valA;
                                      const bIsFile = valB && typeof valB === 'object' && 'path' in valB;
                                      const aIsDir = valA && typeof valA === 'object' && !('path' in valA);
                                      const bIsDir = valB && typeof valB === 'object' && !('path' in valB);
                                      if (aIsDir && !bIsDir) return -1;
                                      if (!aIsDir && bIsDir) return 1;
                                      return a.localeCompare(b);
                                    }) as [deepName, deepValue]}
                                      {#if deepValue && typeof deepValue === 'object' && 'path' in deepValue}
                                        {@const deepFile = deepValue as GitFile}
                                        <div class="tree-item tree-file" class:selected={selectedFile?.path === deepFile.path}>
                                          <button 
                                            onclick={() => fetchFileContent(deepFile)}
                                            class="tree-file-btn"
                                          >
                                            <span class="tree-icon"><Icon name={getFileIconName(deepFile)} size={16} /></span>
                                            <span class="tree-name">{deepName}</span>
                                            {#if deepFile.size}
                                              <span class="tree-size">{formatFileSize(deepFile.size)}</span>
                                            {/if}
                                          </button>
                                        </div>
                                      {:else}
                                        <div class="tree-item tree-folder tree-nested">
                                          <span class="tree-icon">📁</span>
                                          <span class="tree-name">{deepName}/</span>
                                          <span class="tree-note">(deeper nesting not fully expanded)</span>
                                        </div>
                                      {/if}
                                    {/each}
                                  </div>
                                {/if}
                              </div>
                            {/if}
                          {/each}
                        </div>
                      {/if}
                    </div>
                  {/if}
                {/each}
              </div>
            {/if}
          </div>
        {:else if isFile}
          {@const file = value as GitFile}
          <div class="tree-item tree-file" class:selected={selectedFile?.path === file.path}>
            <button 
              onclick={() => fetchFileContent(file)}
              class="tree-file-btn"
            >
              <span class="tree-icon"><Icon name={getFileIconName(file)} size={16} /></span>
              <span class="tree-name">{name}</span>
              {#if file.size}
                <span class="tree-size">{formatFileSize(file.size)}</span>
              {/if}
            </button>
          </div>
        {/if}
      {/each}
    </div>
  </div>

  <div class="file-content-panel">
    {#if loadingContent}
      <div class="file-content-loading">
        <p>Loading file content...</p>
      </div>
    {:else if contentError}
      <div class="file-content-error">
        <p>Error: {contentError}</p>
      </div>
    {:else if selectedFile && (fileContent !== null || fileUrl)}
      <div class="file-content-header">
        <h3 class="file-content-title">{selectedFile.path}</h3>
        <span class="file-content-size">{formatFileSize(selectedFile.size)}</span>
      </div>
      <div class="file-content-body">
        {#if isImageFile(selectedFile) && fileUrl}
          <div class="file-image-container">
            <img src={fileUrl} alt={selectedFile.name} class="file-image" />
          </div>
        {:else if isVideoFile(selectedFile) && fileUrl}
          <div class="file-media-container">
            <video controls class="file-video">
              <source src={fileUrl} type="video/{getFileExtension(selectedFile)}" />
              Your browser does not support the video tag.
            </video>
          </div>
        {:else if isAudioFile(selectedFile) && fileUrl}
          <div class="file-media-container">
            <audio controls class="file-audio">
              <source src={fileUrl} type="audio/{getFileExtension(selectedFile)}" />
              Your browser does not support the audio tag.
            </audio>
          </div>
        {:else if fileContent !== null}
          {#if isCodeFile(selectedFile)}
            <pre class="file-content-code"><code bind:this={codeRef} class="hljs language-{getLanguageFromExtension(selectedFile)}">{fileContent}</code></pre>
          {:else}
            <pre class="file-content-code"><code>{fileContent}</code></pre>
          {/if}
        {/if}
      </div>
    {:else}
      <div class="file-content-empty">
        <p>Select a file to view its contents</p>
      </div>
    {/if}
  </div>
</div>

<style>
  .file-explorer {
    display: flex;
    gap: 1rem;
    height: 1000px;
    min-height: 800px;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.5rem;
    overflow: hidden;
    background: var(--fog-bg, #ffffff);
  }

  :global(.dark) .file-explorer {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-bg, #111827);
  }

  .file-tree-panel {
    flex: 0 0 300px;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--fog-border, #e5e7eb);
    overflow: hidden;
  }

  :global(.dark) .file-tree-panel {
    border-right-color: var(--fog-dark-border, #374151);
  }

  .file-tree-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem;
    border-bottom: 1px solid var(--fog-border, #e5e7eb);
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .file-tree-header {
    border-bottom-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-highlight, #374151);
  }

  .file-tree-title {
    flex: 1;
    font-size: 1rem;
    font-weight: 600;
    margin: 0;
    color: var(--fog-text, #1f2937);
  }

  :global(.dark) .file-tree-title {
    color: var(--fog-dark-text, #f9fafb);
  }

  .expand-all-btn,
  .collapse-all-btn {
    padding: 0.25rem 0.5rem;
    font-size: 0.75rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.25rem;
    background: var(--fog-bg, #ffffff);
    color: var(--fog-text, #1f2937);
    cursor: pointer;
    transition: background-color 0.2s;
  }

  :global(.dark) .expand-all-btn,
  :global(.dark) .collapse-all-btn {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-bg, #111827);
    color: var(--fog-dark-text, #f9fafb);
  }

  .expand-all-btn:hover,
  .collapse-all-btn:hover {
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .expand-all-btn:hover,
  :global(.dark) .collapse-all-btn:hover {
    background: var(--fog-dark-highlight, #475569);
  }

  .file-tree-content {
    flex: 1;
    overflow-y: auto;
    padding: 0.5rem;
  }

  .tree-item {
    display: flex;
    align-items: center;
    font-size: 0.875rem;
  }

  .tree-folder,
  .tree-file {
    margin: 0.125rem 0;
  }

  .tree-nested {
    margin-left: 1rem;
  }

  .tree-folder-btn,
  .tree-file-btn {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.25rem 0.5rem;
    border: none;
    background: none;
    text-align: left;
    cursor: pointer;
    border-radius: 0.25rem;
    transition: background-color 0.2s;
    color: var(--fog-text, #1f2937);
  }

  :global(.dark) .tree-folder-btn,
  :global(.dark) .tree-file-btn {
    color: var(--fog-dark-text, #f9fafb);
  }

  .tree-folder-btn:hover,
  .tree-file-btn:hover {
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .tree-folder-btn:hover,
  :global(.dark) .tree-file-btn:hover {
    background: var(--fog-dark-highlight, #374151);
  }

  .tree-file.selected .tree-file-btn {
    background: var(--fog-accent, #64748b);
    color: var(--fog-bg, #ffffff);
  }

  :global(.dark) .tree-file.selected .tree-file-btn {
    background: var(--fog-dark-accent, #94a3b8);
    color: var(--fog-dark-bg, #111827);
  }

  .tree-icon {
    font-size: 1rem;
    flex-shrink: 0;
  }

  .tree-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .tree-size {
    font-size: 0.75rem;
    color: var(--fog-text-light, #52667a);
    margin-left: 0.5rem;
  }

  :global(.dark) .tree-size {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .tree-children {
    margin-left: 1rem;
    border-left: 1px solid var(--fog-border, #e5e7eb);
    padding-left: 0.5rem;
  }

  :global(.dark) .tree-children {
    border-left-color: var(--fog-dark-border, #374151);
  }

  .tree-note {
    font-size: 0.75rem;
    color: var(--fog-text-light, #52667a);
    font-style: italic;
  }

  :global(.dark) .tree-note {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .file-content-panel {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  .file-content-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem;
    border-bottom: 1px solid var(--fog-border, #e5e7eb);
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .file-content-header {
    border-bottom-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-highlight, #374151);
  }

  .file-content-title {
    font-size: 0.875rem;
    font-weight: 600;
    margin: 0;
    color: var(--fog-text, #1f2937);
    font-family: monospace;
  }

  :global(.dark) .file-content-title {
    color: var(--fog-dark-text, #f9fafb);
  }

  .file-content-size {
    font-size: 0.75rem;
    color: var(--fog-text-light, #52667a);
  }

  :global(.dark) .file-content-size {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .file-content-body {
    flex: 1;
    overflow: auto;
    padding: 1rem;
  }

  /* Code block styling is handled by highlight.js vs2015 theme */

  .file-image-container {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1rem;
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.375rem;
    border: 1px solid var(--fog-border, #e5e7eb);
  }

  :global(.dark) .file-image-container {
    background: var(--fog-dark-highlight, #374151);
    border-color: var(--fog-dark-border, #475569);
  }

  .file-image {
    max-width: 100%;
    max-height: 70vh;
    height: auto;
    border-radius: 0.25rem;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }

  :global(.dark) .file-image {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  }

  .file-media-container {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1rem;
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.375rem;
    border: 1px solid var(--fog-border, #e5e7eb);
  }

  :global(.dark) .file-media-container {
    background: var(--fog-dark-highlight, #374151);
    border-color: var(--fog-dark-border, #475569);
  }

  .file-video {
    max-width: 100%;
    max-height: 70vh;
    border-radius: 0.25rem;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }

  :global(.dark) .file-video {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  }

  .file-audio {
    width: 100%;
    max-width: 600px;
  }

  .file-content-loading,
  .file-content-error,
  .file-content-empty {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--fog-text-light, #52667a);
  }

  :global(.dark) .file-content-loading,
  :global(.dark) .file-content-error,
  :global(.dark) .file-content-empty {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .file-content-error {
    color: var(--fog-error, #dc2626);
  }

  :global(.dark) .file-content-error {
    color: var(--fog-dark-error, #ef4444);
  }

  @media (max-width: 768px) {
    .file-explorer {
      flex-direction: column;
      height: auto;
      min-height: 800px;
      max-height: 1200px;
    }

    .file-tree-panel {
      flex: 0 0 300px;
      border-right: none;
      border-bottom: 1px solid var(--fog-border, #e5e7eb);
    }

    :global(.dark) .file-tree-panel {
      border-bottom-color: var(--fog-dark-border, #374151);
    }
  }
</style>
