<script lang="ts">
  import { onMount, onDestroy } from 'svelte';
  import TopBar from './lib/components/ui/TopBar.svelte';
  import EditorWithLogs from './lib/components/editor/EditorWithLogs.svelte';
  import EditorSettings from './lib/components/editor/EditorSettings.svelte';
  import FileBrowser from './lib/components/ui/FileBrowser.svelte';
  import SidePanel from './lib/components/ui/SidePanel.svelte';
  import ResizablePopup from './lib/components/ui/ResizablePopup.svelte';
  import AudioScope from './lib/components/audio/AudioScope.svelte';
  import Spectrogram from './lib/components/audio/Spectrogram.svelte';
  import ConfirmDialog from './lib/components/ui/ConfirmDialog.svelte';
  import InputDialog from './lib/components/ui/InputDialog.svelte';
  import { createCsoundDerivedStores, type LogEntry } from './lib/csound';
  import { type CsoundProject } from './lib/project-system';
  import { DEFAULT_CSOUND_TEMPLATE } from './lib/config/templates';
  import { createAppContext, setAppContext } from './lib/contexts/app-context';
  import {
    PanelLeftClose,
    PanelLeftOpen,
    PanelRightClose,
    PanelRightOpen,
    PanelBottomClose,
    PanelBottomOpen,
    LayoutGrid,
    Save,
    Share2,
    Activity
  } from 'lucide-svelte';

  const appContext = createAppContext();
  setAppContext(appContext);

  const { csound, projectManager, editorSettings, projectEditor, uiState } = appContext;
  const csoundDerived = createCsoundDerivedStores(csound);

  let analyserNode = $state<AnalyserNode | null>(null);
  let interpreterLogs = $state<LogEntry[]>([]);

  let logsUnsubscribe: (() => void) | undefined;

  onMount(async () => {
    await projectManager.init();

    const result = await projectManager.getAllProjects();
    if (result.success && result.data.length === 0) {
      await projectManager.createProject({
        title: 'Template',
        author: 'System',
        content: DEFAULT_CSOUND_TEMPLATE,
        tags: []
      });
    }

    logsUnsubscribe = csoundDerived.logs.subscribe(logs => {
      interpreterLogs = logs;
    });
  });

  onDestroy(async () => {
    logsUnsubscribe?.();
    await csound.destroy();
  });

  async function handleEnableAudio() {
    try {
      await csound.init();
      uiState.closeAudioPermission();
    } catch (error) {
      console.error('Failed to initialize audio:', error);
    }
  }

  function handleEditorChange(value: string) {
    projectEditor.setContent(value);
  }

  function handleNewFile() {
    const result = projectEditor.requestSwitch(
      () => projectEditor.createNew(DEFAULT_CSOUND_TEMPLATE)
    );

    if (result === 'confirm-unsaved') {
      uiState.showUnsavedChangesDialog();
    }
  }

  function handleFileSelect(project: CsoundProject | null) {
    if (!project) return;

    const result = projectEditor.requestSwitch(
      () => projectEditor.loadProject(project)
    );

    if (result === 'confirm-unsaved') {
      uiState.showUnsavedChangesDialog();
    }
  }

  async function handleExecute(code: string) {
    try {
      await csound.evaluate(code);
    } catch (error) {
      console.error('Execution error:', error);
    }
  }

  async function handleSave() {
    if (projectEditor.isNewUnsavedBuffer) {
      uiState.showSaveAsDialog();
      return;
    }

    await projectEditor.save();
  }

  async function handleSaveAs(title: string) {
    const success = await projectEditor.saveAs(title);
    if (success) {
      uiState.hideSaveAsDialog();
    }
  }

  async function handleMetadataUpdate(projectId: string, updates: { title?: string; author?: string }) {
    await projectEditor.updateMetadata(updates);
  }

  async function handleSwitchSave() {
    const result = await projectEditor.confirmSaveAndSwitch();

    if (result === 'show-save-as') {
      uiState.hideUnsavedChangesDialog();
      uiState.showSaveAsDialog();
    } else {
      uiState.hideUnsavedChangesDialog();
    }
  }

  function handleSwitchDiscard() {
    projectEditor.confirmDiscardAndSwitch();
    uiState.hideUnsavedChangesDialog();
  }

  async function handleShare() {
    if (!projectEditor.currentProjectId) return;

    const result = await projectManager.exportProjectToUrl(projectEditor.currentProjectId);
    if (result.success) {
      try {
        await navigator.clipboard.writeText(result.data);
      } catch (err) {
        console.error('Failed to copy to clipboard:', err);
      }
      uiState.showShare(result.data);
    }
  }

  $effect(() => {
    if (uiState.scopePopupVisible || uiState.spectrogramPopupVisible) {
      analyserNode = csound.getAnalyserNode();

      const unsubscribe = csound.onAnalyserNodeCreated((node) => {
        analyserNode = node;
      });

      return unsubscribe;
    } else {
      analyserNode = null;
    }
  });

  const panelTabs = [
    {
      id: 'editor',
      label: 'Editor',
      content: editorTabContent
    },
    {
      id: 'files',
      label: 'Files',
      content: filesTabContent
    }
  ];
</script>

{#snippet editorTabContent()}
  <EditorSettings />
{/snippet}

{#snippet filesTabContent()}
  <FileBrowser
    {projectManager}
    onFileSelect={handleFileSelect}
    onNewFile={handleNewFile}
    onMetadataUpdate={handleMetadataUpdate}
    selectedProjectId={projectEditor.currentProjectId}
  />
{/snippet}

<div class="app-container">
  <TopBar title="OldBoy">
    {#snippet leftActions()}
      <button
        class="icon-button"
        onclick={handleSave}
        disabled={!projectEditor.hasUnsavedChanges}
        title="Save {projectEditor.hasUnsavedChanges ? '(unsaved changes)' : ''}"
        class:has-changes={projectEditor.hasUnsavedChanges}
      >
        <Save size={18} />
      </button>
    {/snippet}
    <button onclick={() => uiState.toggleSidePanel()} class="icon-button">
      {#if uiState.sidePanelVisible}
        {#if uiState.sidePanelPosition === 'left'}
          <PanelLeftClose size={18} />
        {:else if uiState.sidePanelPosition === 'right'}
          <PanelRightClose size={18} />
        {:else}
          <PanelBottomClose size={18} />
        {/if}
      {:else}
        {#if uiState.sidePanelPosition === 'left'}
          <PanelLeftOpen size={18} />
        {:else if uiState.sidePanelPosition === 'right'}
          <PanelRightOpen size={18} />
        {:else}
          <PanelBottomOpen size={18} />
        {/if}
      {/if}
    </button>
    <button onclick={() => uiState.cyclePanelPosition()} class="icon-button" title="Change panel position">
      <LayoutGrid size={18} />
    </button>
    <button
      onclick={handleShare}
      class="icon-button"
      disabled={!projectEditor.currentProjectId}
      title="Share project"
    >
      <Share2 size={18} />
    </button>
    <button
      onclick={() => uiState.openScope()}
      class="icon-button"
      title="Open audio scope"
    >
      <Activity size={18} />
    </button>
    <button
      onclick={() => uiState.openSpectrogram()}
      class="icon-button"
      title="Open spectrogram"
    >
      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
        <rect x="3" y="3" width="18" height="18" rx="2"/>
        <path d="M3 9h18"/>
        <path d="M3 15h18"/>
        <path d="M9 3v18"/>
        <path d="M15 3v18"/>
      </svg>
    </button>
  </TopBar>

  <div class="main-content" class:panel-bottom={uiState.sidePanelPosition === 'bottom'}>
    {#if uiState.sidePanelPosition === 'left'}
      <SidePanel
        bind:visible={uiState.sidePanelVisible}
        bind:position={uiState.sidePanelPosition}
        tabs={panelTabs}
      />
    {/if}

    <div class="editor-area">
      <EditorWithLogs
        value={projectEditor.content}
        language="javascript"
        onChange={handleEditorChange}
        onExecute={handleExecute}
        logs={interpreterLogs}
        {editorSettings}
      />
    </div>

    {#if uiState.sidePanelPosition === 'right'}
      <SidePanel
        bind:visible={uiState.sidePanelVisible}
        bind:position={uiState.sidePanelPosition}
        tabs={panelTabs}
      />
    {/if}

    {#if uiState.sidePanelPosition === 'bottom'}
      <SidePanel
        bind:visible={uiState.sidePanelVisible}
        bind:position={uiState.sidePanelPosition}
        initialWidth={200}
        minWidth={100}
        maxWidth={400}
        tabs={panelTabs}
      />
    {/if}
  </div>

  <ResizablePopup
    bind:visible={uiState.sharePopupVisible}
    title="Share Project"
    x={(typeof window !== 'undefined' ? window.innerWidth / 2 - 300 : 300)}
    y={(typeof window !== 'undefined' ? window.innerHeight / 2 - 100 : 200)}
    width={600}
    height={200}
    minWidth={400}
    minHeight={150}
  >
    {#snippet children()}
      <div class="share-content">
        <p>Link copied to clipboard!</p>
        <div class="share-url-container">
          <input
            type="text"
            readonly
            value={uiState.shareUrl}
            class="share-url-input"
            onclick={(e) => e.currentTarget.select()}
          />
        </div>
        <p class="share-instructions">Anyone with this link can import the project.</p>
      </div>
    {/snippet}
  </ResizablePopup>

  <ResizablePopup
    visible={uiState.audioPermissionPopupVisible}
    title="Audio Permission Required"
    x={(typeof window !== 'undefined' ? window.innerWidth / 2 - 250 : 250)}
    y={(typeof window !== 'undefined' ? window.innerHeight / 2 - 175 : 200)}
    width={500}
    height={350}
    minWidth={400}
    minHeight={300}
    closable={false}
  >
    {#snippet children()}
      <div class="audio-permission-content">
        <h3>Enable Audio Context</h3>
        <p>OldBoy needs permission to use audio playback.</p>
        <p>Click the button below to enable audio and start using the application.</p>
        <button class="enable-audio-button" onclick={handleEnableAudio}>
          Enable Audio
        </button>
      </div>
    {/snippet}
  </ResizablePopup>

  <ResizablePopup
    bind:visible={uiState.scopePopupVisible}
    title="Audio Scope"
    x={(typeof window !== 'undefined' ? window.innerWidth / 2 - 400 : 100)}
    y={(typeof window !== 'undefined' ? window.innerHeight / 2 - 300 : 100)}
    width={800}
    height={600}
    minWidth={400}
    minHeight={300}
    noPadding={true}
  >
    {#snippet children()}
      <AudioScope analyserNode={analyserNode} />
    {/snippet}
  </ResizablePopup>

  <ResizablePopup
    bind:visible={uiState.spectrogramPopupVisible}
    title="Spectrogram"
    x={(typeof window !== 'undefined' ? window.innerWidth / 2 - 400 : 150)}
    y={(typeof window !== 'undefined' ? window.innerHeight / 2 - 300 : 150)}
    width={800}
    height={600}
    minWidth={400}
    minHeight={300}
    noPadding={true}
  >
    {#snippet children()}
      <Spectrogram analyserNode={analyserNode} />
    {/snippet}
  </ResizablePopup>

  <ConfirmDialog
    bind:visible={uiState.unsavedChangesDialogVisible}
    title="Unsaved Changes"
    message="You have unsaved changes. What would you like to do?"
    confirmLabel="Save"
    cancelLabel="Discard"
    onConfirm={handleSwitchSave}
    onCancel={handleSwitchDiscard}
  />

  <InputDialog
    bind:visible={uiState.saveAsDialogVisible}
    title="Save As"
    label="File name"
    placeholder="Untitled"
    onConfirm={handleSaveAs}
  />
</div>

<style>
  .app-container {
    display: flex;
    flex-direction: column;
    height: 100vh;
    width: 100vw;
    overflow: hidden;
  }

  .main-content {
    display: flex;
    flex: 1;
    overflow: hidden;
  }

  .main-content.panel-bottom {
    flex-direction: column;
  }

  .editor-area {
    flex: 1;
    overflow: hidden;
  }

  .icon-button {
    padding: 0.5rem;
    background-color: #333;
    color: rgba(255, 255, 255, 0.87);
    border: 1px solid #555;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.2s;
  }

  .icon-button:hover:not(:disabled) {
    background-color: #444;
    border-color: #646cff;
  }

  .icon-button:disabled {
    opacity: 0.3;
    cursor: not-allowed;
  }

  .icon-button.has-changes {
    color: #646cff;
  }

  h3 {
    margin-top: 0;
    color: rgba(255, 255, 255, 0.87);
  }

  p {
    color: rgba(255, 255, 255, 0.7);
    line-height: 1.6;
  }

  .share-content {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }

  .share-url-container {
    width: 100%;
  }

  .share-url-input {
    width: 100%;
    padding: 0.75rem;
    background-color: #2a2a2a;
    border: 1px solid #3a3a3a;
    color: rgba(255, 255, 255, 0.87);
    font-size: 0.875rem;
    font-family: monospace;
    outline: none;
    box-sizing: border-box;
  }

  .share-url-input:focus {
    border-color: #646cff;
  }

  .share-instructions {
    font-size: 0.875rem;
    color: rgba(255, 255, 255, 0.5);
    margin: 0;
  }

  .audio-permission-content {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    align-items: center;
    text-align: center;
    padding: 1rem;
  }

  .audio-permission-content h3 {
    margin: 0;
    font-size: 1.25rem;
  }

  .audio-permission-content p {
    margin: 0;
    font-size: 0.95rem;
  }

  .enable-audio-button {
    margin-top: 1rem;
    padding: 0.75rem 2rem;
    background-color: #646cff;
    color: white;
    border: none;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.2s;
  }

  .enable-audio-button:hover {
    background-color: #535bdb;
  }

  .enable-audio-button:active {
    background-color: #424ab8;
  }
</style>

