import {
  Component,
  computed,
  effect,
  inject,
  signal
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { DesktopAppUpdateService } from '../../../../core/services/desktop-app-update.service';
import { MobileAppUpdateService, type MobileUpdateStatus } from '../../../../infrastructure/mobile';
import { APP_TRANSLATE_IMPORTS, AppI18nService } from '../../../../core/i18n';

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, ...APP_TRANSLATE_IMPORTS],
  templateUrl: './updates-settings.component.html'
})
export class UpdatesSettingsComponent {
  private readonly appI18n = inject(AppI18nService);
  readonly desktopUpdates = inject(DesktopAppUpdateService);
  readonly mobileUpdates = inject(MobileAppUpdateService);
  readonly isElectron = this.desktopUpdates.isElectron;
  readonly isCapacitor = this.mobileUpdates.isCapacitor;
  readonly state = this.desktopUpdates.state;
  readonly mobileState = this.mobileUpdates.state;
  readonly mobileStatusLabel = computed(() =>
    this.getMobileStatusLabel(this.mobileState().status)
  );
  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.desktopUpdates.saveUpdatePreferences(mode, preferredVersion);
  }

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

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

  async refreshReleaseInfo(): Promise<void> {
    await this.desktopUpdates.refreshServerContext();
    await this.desktopUpdates.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.desktopUpdates.saveManifestUrls(
      this.parseManifestUrls(this.manifestUrlsText())
    );

    this.hasPendingManifestUrlChanges.set(false);
  }

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

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

  async refreshMobileReleaseInfo(): Promise<void> {
    await this.mobileUpdates.checkForUpdates();
  }

  async openMobileAppStore(): Promise<void> {
    await this.mobileUpdates.openAppStore();
  }

  async installMobileUpdateNow(): Promise<void> {
    const mobileState = this.mobileState();

    if (mobileState.immediateUpdateAllowed) {
      await this.mobileUpdates.performImmediateUpdate();
      return;
    }

    if (mobileState.flexibleUpdateAllowed) {
      await this.mobileUpdates.startFlexibleUpdate();
    }
  }

  async completeMobileFlexibleUpdate(): Promise<void> {
    await this.mobileUpdates.completeFlexibleUpdate();
  }

  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 {
    const keyMap: Record<DesktopUpdateStatus, string> = {
      idle: 'settings.updates.statusLabels.idle',
      checking: 'settings.updates.statusLabels.checking',
      downloading: 'settings.updates.statusLabels.downloading',
      'restart-required': 'settings.updates.statusLabels.restartRequired',
      'up-to-date': 'settings.updates.statusLabels.upToDate',
      disabled: 'settings.updates.statusLabels.disabled',
      unsupported: 'settings.updates.statusLabels.unsupported',
      'no-manifest': 'settings.updates.statusLabels.manifestMissing',
      'target-unavailable': 'settings.updates.statusLabels.versionUnavailable',
      'target-older-than-installed': 'settings.updates.statusLabels.pinnedBelowCurrent',
      error: 'settings.updates.statusLabels.error'
    };

    return this.appI18n.instant(keyMap[status] ?? keyMap['idle']);
  }

  private getMobileStatusLabel(status: MobileUpdateStatus): string {
    const keyMap: Record<string, string> = {
      idle: 'settings.updates.mobileStatusLabels.idle',
      checking: 'settings.updates.mobileStatusLabels.checking',
      downloading: 'settings.updates.mobileStatusLabels.downloading',
      'up-to-date': 'settings.updates.mobileStatusLabels.upToDate',
      'update-available': 'settings.updates.mobileStatusLabels.updateAvailable',
      unsupported: 'settings.updates.mobileStatusLabels.unsupported',
      error: 'settings.updates.mobileStatusLabels.error'
    };

    return this.appI18n.instant(keyMap[status] ?? keyMap['idle']);
  }
}
