import { Injectable, signal, inject } from '@angular/core';
import { HttpClient, HttpEventType } from '@angular/common/http';
import { Storage } from '@ionic/storage-angular';
import { SettingsService } from './settings.service';

export interface Canto {
  id: string;
  id_canti: number;
  titolo: string;
  testo: string;
  accordi?: string;
  autore?: string;
  link_youtube?: string;
  id_momenti?: number[];
  data_update?: string;
  nonValidato?: boolean;
  isPersonal?: boolean;
}

export interface Indice {
  id: number;
  tag_name: string;
  slug: string;
  type: 'liturgico' | 'tematico';
}

export interface CantoEseguito {
  id_canti: number;
  num: number;
}

@Injectable({
  providedIn: 'root'
})
export class CantiService {
  private http = inject(HttpClient);
  private storage = inject(Storage);
  private settingsService = inject(SettingsService);

  private _storage: Storage | null = null;
  public canti = signal<Canto[]>([]);
  public indiceLiturgico = signal<Indice[]>([]);
  public indiceTematico = signal<Indice[]>([]);
  public cantiEseguiti = signal<CantoEseguito[]>([]);
  // Keep momenti for backward compatibility or temporary usage
  public momenti = signal<Indice[]>([]);
  public loading = signal<boolean>(false);
  public progress = signal<number>(0);
  public firstLoadCompleted = signal<boolean>(false);

  private API_URL = 'https://www.canticristiani.it/api/canti.json';

  constructor() {
    this.init();
  }

  async init() {
    const storage = await this.storage.create();
    this._storage = storage;
    await this.loadFromStorage();
    if (this.canti() && this.canti().length > 0) {
      this.firstLoadCompleted.set(true);
    } else {
      // First boot or data cleared: show setup loader immediately
      if ((window as any).PwaLoader) {
        (window as any).PwaLoader.show();
        (window as any).PwaLoader.update({
          title: 'Setup in corso',
          phase: 'Fase: Setup',
          desc: 'Configurazione iniziale e caricamento canti...',
          percent: 0
        });
      }
    }
    this.refresh();
  }

  async loadFromStorage() {
    const cachedCanti = await this._storage?.get('canti');
    const cachedLit = await this._storage?.get('indiceLiturgico');
    const cachedTem = await this._storage?.get('indiceTematico');
    const cachedEseguiti = await this._storage?.get('cantiEseguiti');
    if (cachedCanti) this.canti.set(cachedCanti);
    if (cachedLit) this.indiceLiturgico.set(cachedLit);
    if (cachedTem) this.indiceTematico.set(cachedTem);
    if (cachedEseguiti) this.cantiEseguiti.set(cachedEseguiti);
    // Sync momenti
    if (cachedLit) this.momenti.set(cachedLit);
  }

  refresh() {
    this.loading.set(true);
    this.progress.set(0);
    
    this.http.get(`${this.API_URL}?t=${Date.now()}`, {
      reportProgress: true,
      observe: 'events'
    }).subscribe({
      next: async (event: any) => {
        if (event.type === HttpEventType.DownloadProgress) {
          let pct = 0;
          if (event.total) {
            pct = Math.round((event.loaded / event.total) * 100);
            this.progress.set(pct);
          } else {
            this.progress.update(p => p < 90 ? p + 5 : p);
            pct = this.progress();
          }
          if (!this.firstLoadCompleted() && (window as any).PwaLoader) {
            (window as any).PwaLoader.update({ percent: pct });
          }
        } else if (event.type === HttpEventType.Response) {
          const response = event.body;
          if (response?.canti?.data) {
            const cantiData = response.canti.data;
            const litData = (response.indice_liturgico?.data || []).map((x: any) => ({
              id: x.id_indice_liturgico,
              tag_name: x.tag_name,
              slug: x.slug,
              type: 'liturgico'
            }));
            const temData = (response.indice_tematico?.data || []).map((x: any) => ({
              id: x.id_indice_tematico,
              tag_name: x.tag_name,
              slug: x.slug,
              type: 'tematico'
            }));
            const pivotData = response.tema?.data || [];

            // Optimize linking: O(N+M) instead of O(N*M)
            const pivotMap = new Map<number, number[]>();
            pivotData.forEach((p: any) => {
              if (!pivotMap.has(p.id_canti)) pivotMap.set(p.id_canti, []);
              pivotMap.get(p.id_canti)!.push(p.id_momento);
            });

            const linkedCanti = cantiData.map((c: any) => ({
              ...c,
              id: c.id_canti.toString(),
              id_momenti: pivotMap.get(c.id_canti) || []
            }));

            const eseguitiData = response.canti_eseguiti?.data || [];

            this.canti.set(linkedCanti);
            this.indiceLiturgico.set(litData);
            this.indiceTematico.set(temData);
            this.momenti.set(litData); // Fallback
            this.cantiEseguiti.set(eseguitiData);
            
            await this._storage?.set('canti', linkedCanti);
            await this._storage?.set('indiceLiturgico', litData);
            await this._storage?.set('indiceTematico', temData);
            await this._storage?.set('cantiEseguiti', eseguitiData);
          }
          this.progress.set(100);
          this.loading.set(false);
          this.firstLoadCompleted.set(true);
        }
      },
      error: (error) => {
        console.error('Failed to fetch canti', error);
        this.loading.set(false);
        this.firstLoadCompleted.set(true);
      }
    });
  }

  getCantoById(id: string) {
    return this.canti().find(c => c.id === id);
  }

  getSongTags(canto: Canto): string[] {
    if (!canto.id_momenti || canto.id_momenti.length === 0) return [];
    const tags: string[] = [];
    const lit = this.indiceLiturgico();
    const tem = this.indiceTematico();
    
    canto.id_momenti.forEach(id => {
      const matchLit = lit.find(x => x.id === id);
      if (matchLit) {
        tags.push(matchLit.tag_name);
      } else {
        const matchTem = tem.find(x => x.id === id);
        if (matchTem) {
          tags.push(matchTem.tag_name);
        }
      }
    });
    return tags;
  }

  formatUpdateDate(dateStr: string | undefined): string {
    if (!dateStr) return '';
    try {
      const parts = dateStr.split(' ')[0].split('-');
      if (parts.length === 3) {
        return `${parts[2]}/${parts[1]}/${parts[0]}`;
      }
    } catch (e) {}
    return dateStr;
  }

  getYoutubeId(urlOrId: string | undefined): string | null {
    if (!urlOrId) return null;
    if (urlOrId.length === 11) return urlOrId;
    
    const regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
    const match = urlOrId.match(regExp);
    return (match && match[7].length === 11) ? match[7] : null;
  }

  getYoutubeThumb(urlOrId: string | undefined): string | null {
    const id = this.getYoutubeId(urlOrId);
    return id ? `https://img.youtube.com/vi/${id}/mqdefault.jpg` : null;
  }

  getStorage() {
    return this._storage;
  }
}
