/**
 * File Browser — right sidebar file tree with drag-and-drop
 */

const FILE_ICONS = {
  // Folders
  directory: '📁',
  // Code
  js: '📄', ts: '📄', jsx: '📄', tsx: '📄',
  py: '🐍', rb: '💎', go: '📄', rs: '🦀',
  // Web
  html: '🌐', css: '🎨', svg: '🎨',
  // Data
  json: '📋', yaml: '📋', yml: '📋', toml: '📋',
  xml: '📋', csv: '📋',
  // Docs
  md: '📝', txt: '📝', rst: '📝',
  // Images
  png: '🖼️', jpg: '🖼️', jpeg: '🖼️', gif: '🖼️',
  webp: '🖼️', ico: '🖼️',
  // Config
  env: '🔒', gitignore: '🔒', lock: '🔒',
  // Default
  default: '📄',
};

function getFileIcon(name, isDirectory) {
  if (isDirectory) return FILE_ICONS.directory;
  const ext = name.split('.').pop()?.toLowerCase() || '';
  return FILE_ICONS[ext] || FILE_ICONS.default;
}

function formatSize(bytes) {
  if (bytes == null) return '';
  if (bytes < 1024) return `${bytes}B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}K`;
  return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
}

function normalizePathForCompare(filePath) {
  return filePath.replace(/\\/g, '/').replace(/\/+$/, '').toLowerCase();
}

export class FileBrowser {
  constructor(container, pathEl, messageInput, upButton = null) {
    this.container = container;
    this.pathEl = pathEl;
    this.messageInput = messageInput;
    this.upButton = upButton;
    this.currentPath = null;
    this.rootPath = null;

    this.setupDropTarget();
    this.updateUpButton();
  }

  isWithinRoot(filePath) {
    if (!this.rootPath || !filePath) return false;
    const target = normalizePathForCompare(filePath);
    const root = normalizePathForCompare(this.rootPath);
    return target === root || target.startsWith(`${root}/`);
  }

  updateUpButton() {
    if (!this.upButton) return;
    const canGoUp = this.getParentPath() != null;
    this.upButton.disabled = !canGoUp;
    this.upButton.classList.toggle('disabled', !canGoUp);
    this.upButton.title = canGoUp ? 'Parent directory' : 'Already at project root';
  }

  async load(dirPath) {
    if (dirPath && this.rootPath && !this.isWithinRoot(dirPath)) {
      this.showError('Path outside working directory');
      return;
    }

    this.container.innerHTML = '<div class="file-loading">Loading…</div>';

    try {
      const url = dirPath
        ? `/api/files?path=${encodeURIComponent(dirPath)}`
        : '/api/files';
      const res = await fetch(url);
      const data = await res.json();

      if (data.root) {
        this.rootPath = data.root;
      }

      if (data.error) {
        this.showError(data.error);
        return;
      }

      this.currentPath = data.path;
      this.pathEl.textContent = data.path;
      this.pathEl.title = data.path;
      this.render(data.items);
      this.updateUpButton();
    } catch (err) {
      this.showError('Failed to load');
    }
  }

  showError(message) {
    this.container.innerHTML = '';
    const el = document.createElement('div');
    el.className = 'file-loading';
    el.textContent = message;
    this.container.appendChild(el);

    if (this.rootPath) {
      const btn = document.createElement('button');
      btn.type = 'button';
      btn.className = 'file-root-btn';
      btn.textContent = 'Back to project root';
      btn.addEventListener('click', () => this.load(this.rootPath));
      this.container.appendChild(btn);
    }

    this.updateUpButton();
  }

  getParentPath() {
    if (!this.currentPath || !this.rootPath) return null;

    const sep = this.currentPath.includes('\\') ? '\\' : '/';
    const parts = this.currentPath.split(/[/\\]/).filter(Boolean);
    if (parts.length <= 1) return null;

    parts.pop();
    let parent;
    if (parts.length === 1 && /^[A-Za-z]:$/.test(parts[0])) {
      parent = `${parts[0]}${sep}`;
    } else {
      parent = parts.join(sep);
    }

    if (!this.isWithinRoot(parent)) {
      return null;
    }

    return parent;
  }

  isAbsolutePath(filePath) {
    return filePath.startsWith('/') || /^[A-Za-z]:[\\/]/.test(filePath);
  }

  insertPathIntoInput(filePath) {
    const input = this.messageInput;
    const start = input.selectionStart;
    const end = input.selectionEnd;
    const before = input.value.substring(0, start);
    const after = input.value.substring(end);
    const needsSpace = before.length > 0 && !/\s$/.test(before);
    const insert = `${needsSpace ? ' ' : ''}${filePath}`;
    input.value = before + insert + after;
    input.selectionStart = input.selectionEnd = start + insert.length;
    input.focus();
    input.dispatchEvent(new Event('input'));
  }

  render(items) {
    this.container.innerHTML = '';

    if (items.length === 0) {
      this.container.innerHTML = '<div class="file-loading">Empty directory</div>';
      return;
    }

    for (const item of items) {
      const itemPath = item.path || (this.currentPath
        ? `${this.currentPath}${this.currentPath.endsWith('/') || this.currentPath.endsWith('\\') ? '' : (this.currentPath.includes('\\') ? '\\' : '/')}${item.name}`
        : item.name);

      const el = document.createElement('div');
      el.className = `file-item${item.isDirectory ? ' directory' : ''}`;
      el.draggable = true;
      el.dataset.path = itemPath;
      el.dataset.name = item.name;
      el.dataset.isDirectory = item.isDirectory;

      const icon = getFileIcon(item.name, item.isDirectory);
      const size = item.isDirectory ? '' : formatSize(item.size);

      el.innerHTML = `
        <span class="file-icon">${icon}</span>
        <span class="file-name" title="${item.name}">${item.name}</span>
        ${size ? `<span class="file-size">${size}</span>` : ''}
      `;

      el.addEventListener('click', () => {
        if (item.isDirectory) {
          if (!this.isWithinRoot(itemPath)) {
            this.showError('Path outside working directory');
            return;
          }
          this.load(itemPath);
        } else {
          this.insertPathIntoInput(itemPath);
        }
      });

      el.addEventListener('dblclick', (e) => {
        e.preventDefault();
        if (!item.isDirectory) {
          this.openNatively(itemPath);
        }
      });

      el.addEventListener('dragstart', (e) => {
        e.dataTransfer.setData('text/plain', itemPath);
        e.dataTransfer.effectAllowed = 'copy';
        el.classList.add('dragging');
      });

      el.addEventListener('dragend', () => {
        el.classList.remove('dragging');
      });

      this.container.appendChild(el);
    }
  }

  async openNatively(filePath) {
    try {
      await fetch('/api/open', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ filePath }),
      });
    } catch (err) {
      console.error('[FileBrowser] Failed to open:', err);
    }
  }

  setupDropTarget() {
    const input = this.messageInput;

    input.addEventListener('dragover', (e) => {
      e.preventDefault();
      e.dataTransfer.dropEffect = 'copy';
      input.classList.add('file-drop-hover');
    });

    input.addEventListener('dragleave', () => {
      input.classList.remove('file-drop-hover');
    });

    input.addEventListener('drop', (e) => {
      e.preventDefault();
      input.classList.remove('file-drop-hover');

      const filePath = e.dataTransfer.getData('text/plain');
      if (filePath && this.isAbsolutePath(filePath)) {
        const start = input.selectionStart;
        const end = input.selectionEnd;
        const before = input.value.substring(0, start);
        const after = input.value.substring(end);
        const insert = filePath;
        input.value = before + insert + after;
        input.selectionStart = input.selectionEnd = start + insert.length;
        input.focus();
        input.dispatchEvent(new Event('input'));
      }
    });
  }
}
