import { Injectable, signal, inject, computed, effect } from '@angular/core';
import { Storage } from '@ionic/storage-angular';
import { Canto, CantiService } from './canti.service';
import { ComunitaService } from './comunita.service';
import * as QRCode from 'qrcode';
import { ToastController } from '@ionic/angular';

@Injectable({
  providedIn: 'root'
})
export class PlaylistService {
  private storage = inject(Storage);
  private cantiService = inject(CantiService);
  private comunitaService = inject(ComunitaService);
  private toastCtrl = inject(ToastController);

  public selectionMode = signal<boolean>(false);
  public selectedIds = signal<Set<string>>(new Set());
  public playlists = signal<any[]>([]); 
  public lastPlaylist = signal<any | null>(null);
  public autoPlayPlaylist = signal<boolean>(false);
  
  public activeListIds = signal<string[]>([]);
  public activeListName = signal<string | null>(null);
  public activePlaylistId = signal<string | null>(null);
  
  private _storage: Storage | null = null;
  private initPromise!: Promise<void>;

  // Community scalette exposed as playlists (only when community filter is active)
  public comunitaPlaylists = computed(() => {
    if (!this.comunitaService.comunitaCode() || !this.comunitaService.isFilterActive()) {
      return [];
    }
    return this.comunitaService.comunitaScalette().map(s => ({
      id: s.id,
      name: s.name,
      ids: s.ids,
      createdAt: s.date,
      isComunita: true
    }));
  });

  // Merged list: personal playlists + community scalette
  public allPlaylists = computed(() => {
    const community = this.comunitaPlaylists();
    const personal = this.playlists();
    if (community.length > 0) {
      return [...community, ...personal.map(p => ({ ...p, isComunita: false }))];
    }
    return personal.map(p => ({ ...p, isComunita: false }));
  });

  constructor() {
    this.initPromise = this.init();

    // Watch for context changes to dynamically reload the correct playlists
    effect(() => {
      // Trigger effect on changes to these signals
      this.comunitaService.comunitaCode();
      this.comunitaService.isFilterActive();
      
      // Load the playlists
      this.loadPlaylistsForCurrentContext();
    }, { allowSignalWrites: true });
  }

  private getPlaylistsStorageKey(): string {
    const code = this.comunitaService.comunitaCode();
    const isCommunityActive = this.comunitaService.isFilterActive();
    if (code && isCommunityActive) {
      return `playlists_comunita_${code}`;
    }
    return 'playlists';
  }

  async init() {
    const storage = await this.storage.create();
    this._storage = storage;
    await this.loadPlaylistsForCurrentContext();
  }

  async loadPlaylistsForCurrentContext() {
    if (!this._storage) return;
    const key = this.getPlaylistsStorageKey();
    const saved = await this._storage.get(key);
    this.playlists.set(saved || []);
    
    const lastKey = `lastPlaylist_${key}`;
    const last = await this._storage.get(lastKey);
    this.lastPlaylist.set(last || null);
  }

  toggleSelectionMode() {
    this.selectionMode.update(v => !v);
    if (!this.selectionMode()) {
      this.selectedIds.set(new Set());
    }
  }

  toggleSongSelection(id: string) {
    if (!this.selectionMode()) {
      const active = this.activeListIds();
      if (active.length > 0) {
        this.selectedIds.set(new Set(active));
      }
      this.selectionMode.set(true);
    }
    this.selectedIds.update(set => {
      const newSet = new Set(set);
      if (newSet.has(id)) {
        newSet.delete(id);
      } else {
        newSet.add(id);
      }
      return newSet;
    });
  }

  async savePlaylist(name: string, ids: string[], songSettings?: any) {
    await this.initPromise;
    const key = this.getPlaylistsStorageKey();
    const lastKey = `lastPlaylist_${key}`;
    const editId = this.activePlaylistId();
    let newPlaylist: any;
    
    if (editId) {
      this.playlists.update(p => p.map(pl => {
        if (pl.id === editId) {
          const mergedSettings = songSettings || pl.songSettings || {};
          return { ...pl, name, ids, songSettings: mergedSettings };
        }
        return pl;
      }));
      newPlaylist = this.playlists().find(pl => pl.id === editId);
    } else {
      newPlaylist = {
        id: Date.now().toString(),
        name,
        ids,
        songSettings: songSettings || {},
        createdAt: new Date()
      };
      this.playlists.update(p => [newPlaylist, ...p]);
    }

    this.lastPlaylist.set(newPlaylist);
    this.activeListIds.set(ids);
    this.activeListName.set(name);
    await this._storage?.set(key, this.playlists());
    await this._storage?.set(lastKey, newPlaylist);

    // Reset selection mode, IDs and editing state after saving
    this.selectedIds.set(new Set());
    this.selectionMode.set(false);
    this.activePlaylistId.set(newPlaylist.id);
  }

  async updatePlaylistSongSettings(playlistId: string, songId: string, tonalita: number, speed: number) {
    await this.initPromise;
    this.playlists.update(p => p.map(pl => {
      if (pl.id === playlistId) {
        const songSettings = { ...(pl.songSettings || {}) };
        songSettings[songId] = { tonalita, speed };
        return { ...pl, songSettings };
      }
      return pl;
    }));

    const key = this.getPlaylistsStorageKey();
    await this._storage?.set(key, this.playlists());
    
    // Also update lastPlaylist if it is the current one
    const lastKey = `lastPlaylist_${key}`;
    const last = this.lastPlaylist();
    if (last && last.id === playlistId) {
      const updatedLast = this.playlists().find(pl => pl.id === playlistId);
      this.lastPlaylist.set(updatedLast || null);
      await this._storage?.set(lastKey, updatedLast);
    }
  }

  async deletePlaylist(id: string) {
    await this.initPromise;
    const key = this.getPlaylistsStorageKey();
    this.playlists.update(p => p.filter(pl => pl.id !== id));
    await this._storage?.set(key, this.playlists());
  }

  async generateQR(ids: string[], name: string, songSettings?: any): Promise<string> {
    const data = this.getShareLink(ids, name, songSettings);
    return await QRCode.toDataURL(data, {
      width: 400,
      margin: 2,
      color: {
        dark: '#2d3436',
        light: '#ffffff'
      }
    });
  }

  getShareLink(ids: string[], name: string, songSettings?: any): string {
    const mergedSettings = { ...(songSettings || {}) };
    const cc = this.comunitaService.comunitaCode();
    const isCommunityActive = this.comunitaService.isFilterActive();

    if (cc && isCommunityActive) {
      const communitySettings = this.comunitaService.comunitaCantiSettings();
      for (const id of ids) {
        if (mergedSettings[id] === undefined) {
          const cSettings = communitySettings.find(s => 
            s.id_canti === Number(id) || String(s.id_canti) === id
          );
          if (cSettings) {
            const tonalita = cSettings.tonalita !== undefined ? cSettings.tonalita : 0;
            let speed = 2;
            if (cSettings.speed !== undefined && cSettings.speed > 0) {
              speed = Math.max(1, Math.min(10, Math.round(cSettings.speed / 100)));
            }
            mergedSettings[id] = { tonalita, speed };
          }
        }
      }
    }

    const shareObj: any = { name, ids, songSettings: mergedSettings };

    if (cc && isCommunityActive) {
      const communityCantiIds = this.comunitaService.comunitaCantiIds();
      const communityCantiPersonali = this.comunitaService.comunitaCantiPersonali();

      const containsCommunitySong = ids.some(id => {
        const isStandard = communityCantiIds.includes(id) || communityCantiIds.includes(Number(id));
        const isPersonal = communityCantiPersonali.some(cp => cp.id === id);
        return isStandard || isPersonal;
      });

      if (containsCommunitySong) {
        shareObj.comunitaCode = cc;
      }
    }

    const data = JSON.stringify(shareObj);
    // Use btoa safely for UTF-8 strings
    const base64 = btoa(unescape(encodeURIComponent(data)));
    
    // Always use the production URL for sharing links as requested
    const productionUrl = 'https://www.canticristiani.it';
    return `${productionUrl}/?import=${base64}`;
  }

  processImportJson(json: any): boolean {
    if (json && json.name && json.ids) {
      this.activePlaylistId.set(null); // Forza il salvataggio come nuova playlist indipendente ed editabile
      this.activeListIds.set(json.ids);
      this.activeListName.set(json.name);
      // Automatically save to the device!
      this.savePlaylist(json.name, json.ids, json.songSettings);
      return true;
    }
    return false;
  }

  async sharePlaylistQR(ids: string[], name: string, songSettings?: any) {
    const qrImage = await this.generateQR(ids, name, songSettings);
    const shareLink = this.getShareLink(ids, name, songSettings);
    const fileName = `${name.toLowerCase().replace(/\s+/g, '_')}_qr.png`;

    try {
      const res = await fetch(qrImage);
      const blob = await res.blob();
      const file = new File([blob], fileName, { type: 'image/png' });
      
      if (navigator.share && navigator.canShare && navigator.canShare({ files: [file] })) {
        await navigator.share({
          files: [file],
          title: 'Playlist CantiCristiani',
          text: `Ecco la playlist: ${name}\n\nClicca qui per aprirla subito: ${shareLink}`
        });
      } else {
        // Fallback: copia il link negli appunti e scarica l'immagine del QR
        try {
          if (navigator.clipboard) {
            await navigator.clipboard.writeText(shareLink);
            const toast = await this.toastCtrl.create({
              message: 'Link playlist copiato negli appunti! QR Code scaricato.',
              duration: 3000,
              color: 'success'
            });
            await toast.present();
          }
        } catch (clipErr) {
          console.warn('Failed to copy link to clipboard:', clipErr);
        }

        const link = document.createElement('a');
        link.href = qrImage;
        link.download = fileName;
        link.click();
      }
    } catch (err) {
      console.error('Share failed', err);
    }
  }

  async loadPlaylists() {
  }
}
