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

import { getStoredCurrentUserId } from '../../../core/storage/current-user-storage';
import { buildPushDeviceTokenRegistrationPayload, normalizePushPlatform } from '../logic/mobile-push-token.rules';
import { buildRemotePushSkipMessage, resolveRemotePushSkipReason } from '../logic/mobile-push-registration.rules';
import { loadCapacitorDevicePlugin, loadCapacitorPushNotificationsPlugin } from '../adapters/capacitor/capacitor-plugin-loader';
import { loadMetoyouMobilePlugin } from '../adapters/capacitor/metoyou-mobile.plugin';
import { MobilePlatformService } from './mobile-platform.service';

/** Registers FCM/APNs device tokens with the signaling server on Capacitor shells. */
@Injectable({ providedIn: 'root' })
export class MobilePushRegistrationService {
  private readonly mobilePlatform = inject(MobilePlatformService);
  private wired = false;
  private latestToken: string | null = null;

  initialize(): void {
    if (this.wired || !this.mobilePlatform.isCapacitor()) {
      return;
    }

    this.wired = true;
    void this.registerPushListeners();
  }

  async registerCurrentToken(): Promise<void> {
    if (!this.latestToken) {
      return;
    }

    await this.persistToken(this.latestToken);
  }

  private async registerPushListeners(): Promise<void> {
    const PushNotifications = await loadCapacitorPushNotificationsPlugin();
    const Device = await loadCapacitorDevicePlugin();
    const remotePushConfigured = await this.isRemotePushConfigured();
    const skipReason = resolveRemotePushSkipReason({
      hasPushPlugin: !!PushNotifications,
      hasDevicePlugin: !!Device,
      remotePushConfigured
    });

    if (skipReason) {
      console.warn(buildRemotePushSkipMessage(skipReason));
      return;
    }

    const pushNotifications = PushNotifications;

    if (!pushNotifications) {
      return;
    }

    try {
      const permission = await pushNotifications.checkPermissions();

      if (permission.receive === 'prompt') {
        await pushNotifications.requestPermissions();
      }

      await pushNotifications.addListener('registration', (event) => {
        this.latestToken = event.value;
        void this.persistToken(event.value);
      });

      await pushNotifications.addListener('registrationError', (error) => {
        console.warn('[mobile] push registration failed', error);
      });

      await pushNotifications.register();
    } catch (error) {
      console.warn('[mobile] remote push registration skipped after failure', error);
    }
  }

  private async isRemotePushConfigured(): Promise<boolean> {
    const MetoyouMobile = await loadMetoyouMobilePlugin();

    if (!MetoyouMobile) {
      return false;
    }

    try {
      const result = await MetoyouMobile.isRemotePushConfigured();

      return result.configured === true;
    } catch {
      return false;
    }
  }

  private async persistToken(token: string): Promise<void> {
    const userId = getStoredCurrentUserId();

    if (!userId) {
      return;
    }

    const Device = await loadCapacitorDevicePlugin();
    const deviceInfo = Device ? await Device.getInfo() : null;
    const platform = normalizePushPlatform(deviceInfo?.platform ?? '');

    if (!platform) {
      return;
    }

    const payload = buildPushDeviceTokenRegistrationPayload({
      userId,
      token,
      platform
    });
    const serverUrl = this.resolveSignalingServerUrl();

    if (!serverUrl) {
      return;
    }

    try {
      await fetch(`${serverUrl}/api/users/device-tokens`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload)
      });
    } catch (error) {
      console.warn('[mobile] failed to persist push device token', error);
    }
  }

  private resolveSignalingServerUrl(): string | null {
    if (typeof window === 'undefined') {
      return null;
    }

    const configured = window.localStorage.getItem('metoyou.signalServerUrl');

    if (configured) {
      return configured.replace(/\/$/, '');
    }

    return `${window.location.origin}`;
  }
}
