import { Injectable, signal, inject, computed, effect, Injector } 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, AlertController } from '@ionic/angular';
import { SettingsService } from './settings.service';
import { MyCantiService } from './my-canti.service';

@Injectable({
  providedIn: 'root'
})
export class PlaylistService {
  private storage = inject(Storage);
  private cantiService = inject(CantiService);
  private comunitaService = inject(ComunitaService);
  private toastCtrl = inject(ToastController);
  private alertCtrl = inject(AlertController);
  private settingsService = inject(SettingsService);
  private injector = inject(Injector);
  private myCantiService!: MyCantiService;

  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);
  
  public remotePlaylist = signal<any | null>(null);
  public remoteCustomSongs = signal<any[]>([]);
  public remoteShareCanti = signal<Canto[]>([]);
  
  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 + remote playlist
  public allPlaylists = computed(() => {
    const community = this.comunitaPlaylists();
    const personal = this.playlists();
    const remote = this.remotePlaylist();
    
    let list = [...personal.map(p => ({ ...p, isComunita: false, isRemote: false }))];
    if (community.length > 0) {
      list = [...community, ...list];
    }
    if (remote) {
      list = [{ ...remote, isComunita: false, isRemote: true }, ...list];
    }
    return list;
  });

  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 });
  }

  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);

    // Carica la playlist remota persistita e i relativi canti personalizzati
    const remotePl = await this._storage.get('remote_playlist');
    if (remotePl) {
      this.remotePlaylist.set(remotePl);
    }
    const remoteSongs = await this._storage.get('remote_custom_songs');
    if (remoteSongs) {
      this.remoteCustomSongs.set(remoteSongs);
    }
    const remoteShareSongs = await this._storage.get('remote_share_canti');
    if (remoteShareSongs) {
      this.remoteShareCanti.set(remoteShareSongs);
    }

    // Aggiorna in background la playlist remota per sincronizzare eventuali modifiche
    if (remotePl) {
      this.refreshRemotePlaylist();
    }
  }

  async refreshRemotePlaylist() {
    const remotePl = this.remotePlaylist();
    if (!remotePl) return;

    const parts = remotePl.id.split('_');
    if (parts.length < 3) return;
    const uid = parts[1];

    try {
      const response = await fetch(`https://api.canticristiani.it/${uid}.json?cb=${Date.now()}`, { cache: 'no-store' });
      if (!response.ok) return;
      const remoteJson = await response.json();
      if (Array.isArray(remoteJson)) {
        const customSongs = remoteJson
          .filter((item: any) => !item.momenti || !item.momenti.includes('Playlist'))
          .map((item: any) => ({
            id: `my_${item.id_canti}`,
            id_canti: Number(item.id_canti),
            titolo: item.titolo || 'Senza Titolo',
            testo: item.testo || '',
            accordi: item.accordi || (item.testo?.includes('[') ? item.testo : undefined),
            autore: item.autore || '',
            link_youtube: item.link_youtube || '',
            id_momenti: item.momenti?.map((m: any) => Number(m)).filter((m: any) => !isNaN(m)) || []
          }));

        const playlists = remoteJson
          .filter((item: any) => item.momenti && item.momenti.includes('Playlist'))
          .map((item: any) => {
            let songSettings = {};
            if (item.periodi && item.periodi.length > 0) {
              try {
                songSettings = JSON.parse(item.periodi[0]);
              } catch (e) {}
            }
            return {
              id: `remote_${uid}_${item.id_canti}`,
              name: `[Remote] ${item.titolo}`,
              ids: item.testo ? item.testo.split(',') : [],
              songSettings: songSettings,
              createdAt: new Date(),
              isRemote: true
            };
          });

        const updatedPl = playlists.find(p => p.id === remotePl.id);
        if (updatedPl) {
          this.remotePlaylist.set(updatedPl);
          this.remoteCustomSongs.set(customSongs);
          await this._storage?.set('remote_playlist', updatedPl);
          await this._storage?.set('remote_custom_songs', customSongs);
          console.log('[Remote-Sync] Remote playlist and custom songs updated successfully.');
        }
      }
    } catch (err) {
      console.warn('[Remote-Sync] Failed to refresh remote playlist:', err);
    }
  }

  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, setAsLast = true) {
    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]);
    }

    if (setAsLast) {
      this.lastPlaylist.set(newPlaylist);
    }
    this.activeListIds.set(ids);
    this.activeListName.set(name);
    await this._storage?.set(key, this.playlists());
    if (setAsLast) {
      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);

    // Sincronizza automaticamente in background
    this.syncLocalDataToServer();
  }

  async replaceSongIdInPlaylists(oldId: string, newId: string) {
    await this.initPromise;
    this.playlists.update(p => p.map(pl => {
      if (pl.ids && pl.ids.includes(oldId)) {
        const updatedIds = pl.ids.map((id: string) => id === oldId ? newId : id);
        
        // Copia anche i parametri di tonalità/zoom/velocità della canzone se presenti
        const songSettings = { ...(pl.songSettings || {}) };
        if (songSettings[oldId]) {
          songSettings[newId] = { ...songSettings[oldId] };
          delete songSettings[oldId];
        }
        
        return { ...pl, ids: updatedIds, songSettings };
      }
      return pl;
    }));

    const key = this.getPlaylistsStorageKey();
    await this._storage?.set(key, this.playlists());
    
    // Sincronizza automaticamente in background
    this.syncLocalDataToServer();
  }

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

    const key = this.getPlaylistsStorageKey();
    await this._storage?.set(key, this.playlists());

    // Sincronizza automaticamente in background
    this.syncLocalDataToServer();
    
    // 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;
    if (id.startsWith('remote_')) {
      await this.clearRemotePlaylist();
      return;
    }
    const key = this.getPlaylistsStorageKey();
    this.playlists.update(p => p.filter(pl => pl.id !== id));
    await this._storage?.set(key, this.playlists());

    // Sincronizza automaticamente in background
    this.syncLocalDataToServer();
  }

  async saveRemotePlaylist(pl: any, customSongs: any[]) {
    await this.initPromise;
    this.remotePlaylist.set(pl);
    this.remoteCustomSongs.set(customSongs);
    await this._storage?.set('remote_playlist', pl);
    await this._storage?.set('remote_custom_songs', customSongs);
  }

  async clearRemotePlaylist() {
    await this.initPromise;
    this.remotePlaylist.set(null);
    this.remoteCustomSongs.set([]);
    await this._storage?.remove('remote_playlist');
    await this._storage?.remove('remote_custom_songs');

    // Sincronizza automaticamente in background
    this.syncLocalDataToServer();
  }

  async syncLocalDataToServer() {
    await this.initPromise;
    const uid = this.settingsService.userUuid();
    if (!uid) return;

    if (!this.myCantiService) {
      this.myCantiService = this.injector.get(MyCantiService);
    }

    try {
      const mergedSongsMap = new Map<number, any>();

      this.remoteShareCanti().forEach(c => {
        const id_canti = c.id_canti || Date.now();
        mergedSongsMap.set(id_canti, {
          id_canti,
          titolo: c.titolo || 'Senza Titolo',
          autore: c.autore || '',
          link_youtube: c.link_youtube || '',
          accordi: c.accordi || '',
          momenti: c.id_momenti?.map(id => String(id)) || [],
          periodi: [] as string[],
          testo: c.testo || ''
        });
      });

      this.myCantiService.myCanti().forEach(c => {
        const id_canti = c.id_canti || Date.now();
        mergedSongsMap.set(id_canti, {
          id_canti,
          titolo: c.titolo || 'Senza Titolo',
          autore: c.autore || '',
          link_youtube: c.link_youtube || '',
          accordi: c.accordi || '',
          momenti: c.id_momenti?.map(id => String(id)) || [],
          periodi: [] as string[],
          testo: c.testo || ''
        });
      });

      const customSongs = Array.from(mergedSongsMap.values());

      const playlistSongs = this.playlists().map(pl => ({
        id_canti: Number(pl.id) || Date.now(),
        titolo: pl.name,
        momenti: ['Playlist'],
        periodi: pl.songSettings ? [JSON.stringify(pl.songSettings)] : [],
        testo: pl.ids.join(',')
      }));

      const payload = [...customSongs, ...playlistSongs];

      if (this.settingsService.userName()) {
        payload.push({
          id_canti: 999999,
          titolo: this.settingsService.userName(),
          momenti: ['UserMetadata'],
          periodi: [],
          testo: ''
        });
      }

      const response = await fetch('https://api.canticristiani.it/miei', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-user-uid': uid
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        console.warn(`[Auto-Sync] Server returned code: ${response.status}`);
      } else {
        console.log('[Auto-Sync] Local playlists and canti backed up successfully.');
      }
    } catch (err) {
      console.error('[Auto-Sync] Auto-synchronization failed:', err);
    }
  }

  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}&openFirst=1`;
  }

  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, false);
      return true;
    }
    return false;
  }

  async sharePlaylistQR(ids: string[], name: string, songSettings?: any) {
    // Sincronizza istantaneamente sul server prima di generare/condividere la playlist
    await this.syncLocalDataToServer();

    const uid = this.settingsService.userUuid();
    const activeId = this.activePlaylistId() || Date.now().toString();
    const isRemote = activeId.startsWith('remote_');

    const buttons: any[] = [
      {
        text: isRemote ? 'Condividi (Sola Lettura)' : 'Sola Lettura (Consultazione)',
        handler: () => {
          let shareLink = `https://www.canticristiani.it/?playlist-uid=${uid}&playlist-id=${activeId}&openFirst=1`;
          if (isRemote) {
            let remoteUid = uid;
            let remotePid = activeId;
            const parts = activeId.split('_');
            if (parts.length >= 3) {
              remoteUid = parts[1];
              remotePid = parts[2];
            }
            shareLink = `https://www.canticristiani.it/?playlist-uid=${remoteUid}&playlist-id=${remotePid}&openFirst=1`;
          }
          this.executeShare(shareLink, name);
        }
      }
    ];

    if (!isRemote) {
      buttons.push({
        text: 'Modifica (Collaborazione / Backup)',
        handler: () => {
          const shareLink = `https://www.canticristiani.it/?restore-uid=${uid}`;
          this.executeShare(shareLink, name + ' (Editor)');
        }
      });
    }

    buttons.push({
      text: 'Annulla',
      role: 'cancel'
    });

    const alert = await this.alertCtrl.create({
      header: 'Condividi Playlist',
      message: isRemote ? 'Condividi questa playlist in sola lettura:' : 'Scegli la modalità di condivisione della playlist:',
      buttons: buttons
    });
    await alert.present();
  }

  private async executeShare(shareLink: string, name: string) {
    // Generate QR using the link
    const qrImage = await QRCode.toDataURL(shareLink, {
      width: 400,
      margin: 2,
      color: {
        dark: '#2d3436',
        light: '#ffffff'
      }
    });

    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() {
  }

  async saveRemoteShareCanto(canto: Canto) {
    await this.initPromise;
    const current = this.remoteShareCanti();
    const index = current.findIndex(c => c.id === canto.id);
    let updated: Canto[];
    if (index > -1) {
      updated = current.map(c => c.id === canto.id ? canto : c);
    } else {
      updated = [...current, canto];
    }
    this.remoteShareCanti.set(updated);
    await this._storage?.set('remote_share_canti', updated);
  }

  async deleteRemoteShareCanto(id: string) {
    await this.initPromise;
    const updated = this.remoteShareCanti().filter(c => c.id !== id);
    this.remoteShareCanti.set(updated);
    await this._storage?.set('remote_share_canti', updated);
  }
}
