import { useEffect, useState } from 'react';
import type { FileEntry, FileReadResponse } from '@hermes-mobile/shared';
import { useCompanion } from '../../api/CompanionContext.js';

function parentPath(path: string): string {
  if (path === '.') return '.';
  const parts = path.split('/').filter(Boolean);
  parts.pop();
  return parts.length ? parts.join('/') : '.';
}

export function FilesScreen() {
  const { client } = useCompanion();
  const [path, setPath] = useState('.');
  const [entries, setEntries] = useState<FileEntry[]>([]);
  const [activeFile, setActiveFile] = useState<FileReadResponse | null>(null);
  const [draft, setDraft] = useState('');
  const [status, setStatus] = useState('');
  const [busy, setBusy] = useState(false);

  async function loadDirectory(nextPath = path): Promise<void> {
    setBusy(true);
    setStatus('');

    try {
      const response = await client.listFiles(nextPath);
      setPath(response.path);
      setEntries(response.entries);
      setActiveFile(null);
      setDraft('');
    } catch (caughtError) {
      setStatus(caughtError instanceof Error ? caughtError.message : 'Unable to list files');
    } finally {
      setBusy(false);
    }
  }

  async function openEntry(entry: FileEntry): Promise<void> {
    if (entry.type === 'directory') {
      await loadDirectory(entry.path);
      return;
    }

    setBusy(true);
    setStatus('');

    try {
      const response = await client.readFile(entry.path);
      setActiveFile(response);
      setDraft(response.content);
    } catch (caughtError) {
      setStatus(caughtError instanceof Error ? caughtError.message : 'Unable to read file');
    } finally {
      setBusy(false);
    }
  }

  async function saveFile(): Promise<void> {
    if (!activeFile) return;
    setBusy(true);

    try {
      const response = await client.writeFile(activeFile.path, draft);
      setStatus(`Saved ${response.bytesWritten} bytes to ${response.path}`);
      await openEntry({ name: activeFile.path, path: activeFile.path, type: 'file', size: 0, modifiedAt: new Date().toISOString() });
    } catch (caughtError) {
      setStatus(caughtError instanceof Error ? caughtError.message : 'Unable to save file');
    } finally {
      setBusy(false);
    }
  }

  useEffect(() => {
    void loadDirectory('.');
  }, [client]);

  return (
    <section className="screen stack-screen">
      <div className="screen-heading">
        <div>
          <p className="eyebrow">Workspace</p>
          <h2>Files</h2>
        </div>
        <button className="small-button" onClick={() => void loadDirectory()} type="button">Refresh</button>
      </div>

      <article className="panel-card">
        <div className="path-bar">
          <button disabled={path === '.' || busy} onClick={() => void loadDirectory(parentPath(path))} type="button">Up</button>
          <span>{path}</span>
        </div>
        <div className="file-list">
          {entries.map((entry) => (
            <button className="file-row" key={entry.path} onClick={() => void openEntry(entry)} type="button">
              <span>{entry.type === 'directory' ? '📁' : '📄'} {entry.name}</span>
              <small>{entry.type === 'file' ? `${entry.size} B` : 'dir'}</small>
            </button>
          ))}
        </div>
      </article>

      {activeFile ? (
        <article className="panel-card editor-card">
          <div className="screen-heading">
            <div>
              <p className="eyebrow">Editing</p>
              <h3>{activeFile.path}</h3>
            </div>
            <button className="small-button" disabled={busy} onClick={() => void saveFile()} type="button">Save</button>
          </div>
          <textarea aria-label="File content" onChange={(event) => setDraft(event.target.value)} value={draft} />
        </article>
      ) : null}

      {status ? <p className="error-card">{status}</p> : null}
    </section>
  );
}
