import {
  Injectable,
  computed,
  inject,
  signal
} from '@angular/core';
import type { SavedThemeSummary } from '../../domain/models/theme.model';
import { ThemeLibraryStorageService } from '../../infrastructure/services/theme-library-storage.service';
import { ThemeService } from './theme.service';

@Injectable({ providedIn: 'root' })
export class ThemeLibraryService {
  readonly storage = inject(ThemeLibraryStorageService);
  readonly theme = inject(ThemeService);

  readonly isAvailable = signal(this.storage.isAvailable);
  readonly entries = signal<SavedThemeSummary[]>([]);
  readonly selectedFileName = signal<string | null>(null);
  readonly isBusy = signal(false);
  readonly savedThemesPath = signal<string | null>(null);
  readonly selectedEntry = computed(() => {
    const selectedFileName = this.selectedFileName();

    return selectedFileName
      ? this.entries().find((entry) => entry.fileName === selectedFileName) ?? null
      : null;
  });

  async refresh(preferredSelection?: string | null): Promise<void> {
    if (!this.isAvailable() || this.isBusy()) {
      return;
    }

    this.isBusy.set(true);

    try {
      await this.refreshEntries(preferredSelection);
    } catch {
      this.theme.announceStatus('Unable to refresh the saved themes library.');
    } finally {
      this.isBusy.set(false);
    }
  }

  select(fileName: string | null): void {
    this.selectedFileName.set(fileName);
  }

  async useSelectedTheme(): Promise<boolean> {
    const selectedEntry = this.selectedEntry();

    if (!selectedEntry || this.isBusy()) {
      return false;
    }

    const themeText = await this.storage.readThemeText(selectedEntry.fileName);

    if (!themeText) {
      this.theme.announceStatus('Unable to read the selected saved theme.');
      return false;
    }

    return this.theme.loadThemeText(themeText, 'apply', `${selectedEntry.themeName} applied from saved themes.`, 'saved theme');
  }

  async openSelectedThemeInDraft(): Promise<boolean> {
    const selectedEntry = this.selectedEntry();

    if (!selectedEntry || this.isBusy()) {
      return false;
    }

    const themeText = await this.storage.readThemeText(selectedEntry.fileName);

    if (!themeText) {
      this.theme.announceStatus('Unable to read the selected saved theme.');
      return false;
    }

    return this.theme.loadThemeText(themeText, 'draft', `${selectedEntry.themeName} loaded into the draft editor.`, 'saved theme');
  }

  async saveDraftAsNewTheme(): Promise<string | null> {
    if (this.isBusy()) {
      return null;
    }

    if (!this.theme.draftIsValid()) {
      this.theme.announceStatus('Fix JSON errors before saving a theme.');
      return null;
    }

    this.isBusy.set(true);

    try {
      const fileName = await this.storage.saveNewTheme(this.theme.draftTheme().meta.name, this.theme.draftText());

      if (!fileName) {
        this.theme.announceStatus('Unable to save the current draft as a new theme.');
        return null;
      }

      await this.refreshEntries(fileName);
      this.theme.announceStatus(`${this.theme.draftTheme().meta.name} saved to the Electron themes folder.`);
      return fileName;
    } finally {
      this.isBusy.set(false);
    }
  }

  async saveDraftToSelectedTheme(): Promise<boolean> {
    const selectedEntry = this.selectedEntry();

    if (!selectedEntry || this.isBusy()) {
      return false;
    }

    if (!this.theme.draftIsValid()) {
      this.theme.announceStatus('Fix JSON errors before updating a saved theme.');
      return false;
    }

    this.isBusy.set(true);

    try {
      const saved = await this.storage.overwriteTheme(selectedEntry.fileName, this.theme.draftText());

      if (!saved) {
        this.theme.announceStatus('Unable to update the selected saved theme.');
        return false;
      }

      await this.refreshEntries(selectedEntry.fileName);
      this.theme.announceStatus(`${selectedEntry.themeName} updated in the Electron themes folder.`);
      return true;
    } finally {
      this.isBusy.set(false);
    }
  }

  async removeSelectedTheme(): Promise<boolean> {
    const selectedEntry = this.selectedEntry();

    if (!selectedEntry || this.isBusy()) {
      return false;
    }

    this.isBusy.set(true);

    try {
      const deleted = await this.storage.deleteTheme(selectedEntry.fileName);

      if (!deleted) {
        this.theme.announceStatus('Unable to remove the selected saved theme.');
        return false;
      }

      await this.refreshEntries(null);
      this.theme.announceStatus(`${selectedEntry.themeName} removed from saved themes.`);
      return true;
    } finally {
      this.isBusy.set(false);
    }
  }

  private async refreshEntries(preferredSelection?: string | null): Promise<void> {
    const entries = await this.storage.listThemes();
    const savedThemesPath = await this.storage.getSavedThemesPath();
    const nextSelection = preferredSelection ?? this.selectedFileName();

    this.entries.set(entries);
    this.savedThemesPath.set(savedThemesPath);

    if (nextSelection && entries.some((entry) => entry.fileName === nextSelection)) {
      this.selectedFileName.set(nextSelection);
      return;
    }

    this.selectedFileName.set(entries[0]?.fileName ?? null);
  }
}
