import {
  Component,
  computed,
  effect,
  inject,
  signal
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { DesktopAppUpdateService } from '../../../../core/services/desktop-app-update.service';

type AutoUpdateMode = 'auto' | 'off' | 'version';
type DesktopUpdateStatus =
  | 'idle'
  | 'disabled'
  | 'checking'
  | 'downloading'
  | 'up-to-date'
  | 'restart-required'
  | 'unsupported'
  | 'no-manifest'
  | 'target-unavailable'
  | 'target-older-than-installed'
  | 'error';

@Component({
  selector: 'app-updates-settings',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './updates-settings.component.html'
})
export class UpdatesSettingsComponent {
  readonly updates = inject(DesktopAppUpdateService);
  readonly isElectron = this.updates.isElectron;
  readonly state = this.updates.state;
  readonly hasPendingManifestUrlChanges = signal(false);
  readonly manifestUrlsText = signal('');
  readonly statusLabel = computed(() => this.getStatusLabel(this.state().status));
  readonly isUsingConnectedServerDefaults = computed(() => {
    return this.state().configuredManifestUrls.length === 0;
  });

  constructor() {
    effect(() => {
      if (this.hasPendingManifestUrlChanges()) {
        return;
      }

      this.manifestUrlsText.set(this.stringifyManifestUrls(
        this.isUsingConnectedServerDefaults()
          ? this.state().defaultManifestUrls
          : this.state().configuredManifestUrls
      ));
    });
  }

  async onModeChange(event: Event): Promise<void> {
    const select = event.target as HTMLSelectElement;
    const mode = select.value as AutoUpdateMode;
    const preferredVersion = mode === 'version'
      ? this.state().preferredVersion ?? this.state().availableVersions[0] ?? null
      : this.state().preferredVersion;

    await this.updates.saveUpdatePreferences(mode, preferredVersion);
  }

  async onVersionChange(event: Event): Promise<void> {
    const select = event.target as HTMLSelectElement;

    await this.updates.saveUpdatePreferences('version', select.value || null);
  }

  async refreshReleaseInfo(): Promise<void> {
    await this.updates.refreshServerContext();
    await this.updates.checkForUpdates();
  }

  onManifestUrlsInput(event: Event): void {
    const textarea = event.target as HTMLTextAreaElement;

    this.hasPendingManifestUrlChanges.set(true);
    this.manifestUrlsText.set(textarea.value);
  }

  async saveManifestUrls(): Promise<void> {
    await this.updates.saveManifestUrls(
      this.parseManifestUrls(this.manifestUrlsText())
    );

    this.hasPendingManifestUrlChanges.set(false);
  }

  async useConnectedServerDefaults(): Promise<void> {
    await this.updates.saveManifestUrls([]);
    this.hasPendingManifestUrlChanges.set(false);
  }

  async restartNow(): Promise<void> {
    await this.updates.restartToApplyUpdate();
  }

  private parseManifestUrls(rawValue: string): string[] {
    return [
      ...new Set(
        rawValue
          .split(/\r?\n/)
          .map((entry) => entry.trim())
          .filter((entry) => entry.length > 0)
      )
    ];
  }

  private stringifyManifestUrls(manifestUrls: string[]): string {
    return manifestUrls.join('\n');
  }

  private getStatusLabel(status: DesktopUpdateStatus): string {
    switch (status) {
      case 'checking':
        return 'Checking';
      case 'downloading':
        return 'Downloading';
      case 'restart-required':
        return 'Restart required';
      case 'up-to-date':
        return 'Up to date';
      case 'disabled':
        return 'Disabled';
      case 'unsupported':
        return 'Unsupported';
      case 'no-manifest':
        return 'Manifest missing';
      case 'target-unavailable':
        return 'Version unavailable';
      case 'target-older-than-installed':
        return 'Pinned below current';
      case 'error':
        return 'Error';
      default:
        return 'Idle';
    }
  }
}
