import {
  Injectable,
  inject,
  signal
} from '@angular/core';

import { WebMobileAppUpdateAdapter } from '../adapters/web/web-mobile-app-update.adapter';
import type { MobileAppUpdateAdapter } from '../contracts/mobile.contracts';
import { AppI18nService } from '../../../core/i18n';
import { resolveMobileAdapter } from '../logic/mobile-capacitor-adapter.rules';
import {
  buildMobileUpdateState,
  createInitialMobileUpdateState,
  resolveMobileUpdateStatusMessage,
  type MobileUpdateState
} from '../logic/mobile-app-update.rules';
import { MobilePlatformService } from './mobile-platform.service';

const DEFAULT_POLL_INTERVAL_MS = 30 * 60_000;

@Injectable({ providedIn: 'root' })
export class MobileAppUpdateService {
  readonly state = signal<MobileUpdateState>(createInitialMobileUpdateState());

  private readonly appI18n = inject(AppI18nService);
  private readonly mobilePlatform = inject(MobilePlatformService);
  private adapter: MobileAppUpdateAdapter = new WebMobileAppUpdateAdapter();
  private adapterReady: Promise<MobileAppUpdateAdapter> | null = null;
  private initialized = false;
  private pollTimerId: number | null = null;

  get isCapacitor(): boolean {
    return this.mobilePlatform.isCapacitor();
  }

  async initialize(): Promise<void> {
    if (this.initialized) {
      return;
    }

    this.initialized = true;

    const adapter = await this.ensureAdapter();

    this.state.set(createInitialMobileUpdateState({
      isSupported: adapter.isSupported,
      translate: (key, params) => this.appI18n.instant(key, params)
    }));

    if (!adapter.isSupported) {
      return;
    }

    this.startPolling();
    await this.checkForUpdates();
  }

  async checkForUpdates(): Promise<void> {
    const adapter = await this.ensureAdapter();

    if (!adapter.isSupported) {
      return;
    }

    this.state.update((current) => ({
      ...current,
      status: 'checking',
      statusMessage: resolveMobileUpdateStatusMessage('checking', null, null, (key, params) => this.appI18n.instant(key, params))
    }));

    try {
      const snapshot = await adapter.getAppUpdateInfo();

      this.state.set(buildMobileUpdateState(snapshot, {
        isSupported: true,
        lastCheckedAt: Date.now(),
        translate: (key, params) => this.appI18n.instant(key, params)
      }));
    } catch (error) {
      this.state.set({
        ...createInitialMobileUpdateState({
          isSupported: true,
          translate: (key, params) => this.appI18n.instant(key, params)
        }),
        lastCheckedAt: Date.now(),
        status: 'error',
        statusMessage: resolveMobileUpdateStatusMessage('error', error, null, (key, params) => this.appI18n.instant(key, params))
      });
    }
  }

  async openAppStore(): Promise<void> {
    const adapter = await this.ensureAdapter();

    if (!adapter.isSupported) {
      return;
    }

    await adapter.openAppStore();
  }

  async performImmediateUpdate(): Promise<void> {
    const adapter = await this.ensureAdapter();

    if (!adapter.isSupported) {
      return;
    }

    this.state.update((current) => ({
      ...current,
      status: 'downloading',
      statusMessage: resolveMobileUpdateStatusMessage('downloading', null, null, (key, params) => this.appI18n.instant(key, params))
    }));

    await adapter.performImmediateUpdate();
  }

  async startFlexibleUpdate(): Promise<void> {
    const adapter = await this.ensureAdapter();

    if (!adapter.isSupported) {
      return;
    }

    this.state.update((current) => ({
      ...current,
      status: 'downloading',
      statusMessage: resolveMobileUpdateStatusMessage('downloading', null, null, (key, params) => this.appI18n.instant(key, params))
    }));

    await adapter.startFlexibleUpdate();
  }

  async completeFlexibleUpdate(): Promise<void> {
    const adapter = await this.ensureAdapter();

    if (!adapter.isSupported) {
      return;
    }

    await adapter.completeFlexibleUpdate();
  }

  private ensureAdapter(): Promise<MobileAppUpdateAdapter> {
    if (!this.adapterReady) {
      this.adapterReady = resolveMobileAdapter(
        this.mobilePlatform.runtime(),
        this.adapter,
        async () => {
          const { CapacitorMobileAppUpdateAdapter } = await import('../adapters/capacitor/capacitor-mobile-app-update.adapter');

          return new CapacitorMobileAppUpdateAdapter();
        }
      ).then((adapter) => {
        this.adapter = adapter;
        this.mobilePlatform.refreshRuntimeDetection();
        return adapter;
      });
    }

    return this.adapterReady;
  }

  private startPolling(): void {
    if (this.pollTimerId !== null || typeof window === 'undefined') {
      return;
    }

    this.pollTimerId = window.setInterval(() => {
      void this.checkForUpdates();
    }, DEFAULT_POLL_INTERVAL_MS);
  }
}
