// lib/db/services/POWRPackService.ts
import { SQLiteDatabase } from 'expo-sqlite';
import NDK, { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk-mobile';
import { nip19 } from 'nostr-tools';
import { generateId } from '@/utils/ids';
import { NostrIntegration } from './NostrIntegration';
import { POWRPack, POWRPackImport, POWRPackSelection, POWRPackWithContent } from '@/types/powr-pack';
import { 
  BaseExercise, 
  ExerciseType, 
  ExerciseCategory 
} from '@/types/exercise';
import { 
  WorkoutTemplate, 
  TemplateType 
} from '@/types/templates';
import '@/types/ndk-extensions';
import { safeAddRelay, safeRemoveRelay } from '@/types/ndk-common';
import { useLibraryStore } from '@/lib/stores/libraryStore';

/**
 * Service for managing POWR Packs (importable collections of templates and exercises)
 */
export default class POWRPackService {
  private db: SQLiteDatabase;
  private nostrIntegration: NostrIntegration;
  private exerciseWithRelays: Map<string, {event: NDKEvent, relays: string[]}> = new Map();
  
  constructor(db: SQLiteDatabase) {
    this.db = db;
    this.nostrIntegration = new NostrIntegration(db);
  }
  
   /**
   * Fetch a POWR Pack from a Nostr address (naddr)
   */
  async fetchPackFromNaddr(naddr: string, ndk: NDK): Promise<POWRPackImport> {
    try {
      console.log(`Fetching POWR Pack from naddr: ${naddr}`);
      
      // Validate naddr format
      if (!naddr.startsWith('naddr1')) {
        throw new Error('Invalid naddr format. Should start with "naddr1"');
      }
      
      // Decode naddr
      const decoded = nip19.decode(naddr);
      if (decoded.type !== 'naddr') {
        throw new Error('Invalid naddr format');
      }
      
      const { pubkey, kind, identifier, relays } = decoded.data;
      console.log(`Decoded naddr: pubkey=${pubkey}, kind=${kind}, identifier=${identifier}`);
      console.log(`Relay hints: ${relays ? relays.join(', ') : 'none'}`);
      
      // Track temporarily added relays
      const addedRelays = new Set<string>();
      
      // If relay hints are provided, add them to NDK's pool temporarily
      if (relays && relays.length > 0) {
        for (const relay of relays) {
          try {
            console.log(`Adding suggested relay: ${relay}`);
            // Use type assertion
            this.safeAddRelay(ndk, relay);
            addedRelays.add(relay);
          } catch (error) {
            console.warn(`Failed to add relay ${relay}:`, error);
          }
        }
      }
      
      // Create filter to fetch the pack event
      const packFilter: NDKFilter = {
        kinds: [kind],
        authors: [pubkey],
        '#d': identifier ? [identifier] : undefined
      };
      
      console.log(`Fetching pack with filter: ${JSON.stringify(packFilter)}`);
      
      // Fetch the pack event
      const events = await ndk.fetchEvents(packFilter);
      
      // Clean up - remove any temporarily added relays
      if (addedRelays.size > 0) {
        console.log(`Removing ${addedRelays.size} temporarily added relays`);
        for (const relay of addedRelays) {
          try {
            this.safeRemoveRelay(ndk, relay);
          } catch (err) {
            console.warn(`Failed to remove relay ${relay}:`, err);
          }
        }
      }
      
      if (events.size === 0) {
        throw new Error('Pack not found');
      }
      
      // Get the first matching event
      const packEvent = Array.from(events)[0];
      console.log(`Fetched pack event: ${packEvent.id}`);
      
      // Get tags for debugging
      console.log(`Pack tags: ${JSON.stringify(packEvent.tags)}`);
      
      // Extract template and exercise references
      const templateRefs: string[] = [];
      const exerciseRefs: string[] = [];
      
      // Use NDK's getMatchingTags for more reliable tag handling
      const aTags = packEvent.getMatchingTags('a');
      
      for (const tag of aTags) {
        if (tag.length < 2) continue;
        
        const addressPointer = tag[1];
        if (addressPointer.startsWith('33402:')) {
          console.log(`Found template reference: ${addressPointer}`);
          
          // Include any relay hints in the tag
          if (tag.length > 2) {
            const relayHints = tag.slice(2).filter(r => r.startsWith('wss://'));
            if (relayHints.length > 0) {
              templateRefs.push(`${addressPointer},${relayHints.join(',')}`);
              continue;
            }
          }
          
          templateRefs.push(addressPointer);
        } else if (addressPointer.startsWith('33401:')) {
          console.log(`Found exercise reference: ${addressPointer}`);
          
          // Include any relay hints in the tag
          if (tag.length > 2) {
            const relayHints = tag.slice(2).filter(r => r.startsWith('wss://'));
            if (relayHints.length > 0) {
              exerciseRefs.push(`${addressPointer},${relayHints.join(',')}`);
              continue;
            }
          }
          
          exerciseRefs.push(addressPointer);
        }
      }
      
      console.log(`Found ${templateRefs.length} template refs and ${exerciseRefs.length} exercise refs`);
      
      // Fetch referenced templates and exercises
      const templates = await this.fetchReferencedEvents(ndk, templateRefs);
      const exercises = await this.fetchReferencedEvents(ndk, exerciseRefs);
      
      console.log(`Fetched ${templates.length} templates and ${exercises.length} exercises`);
      
      return {
        packEvent,
        templates,
        exercises
      };
    } catch (error) {
      console.error('Error fetching pack from naddr:', error);
      throw error;
    }
  }
  
  /**
   * Fetch referenced events (templates or exercises)
   */
  async fetchReferencedEvents(ndk: NDK, refs: string[]): Promise<NDKEvent[]> {
    if (refs.length === 0) return [];
    
    console.log(`Fetching references: ${JSON.stringify(refs)}`);
    
    const events: NDKEvent[] = [];
    const addedRelays: Set<string> = new Set(); // Track temporarily added relays
    
    for (const ref of refs) {
      try {
        // Parse the reference format (kind:pubkey:d-tag,relay1,relay2)
        const parts = ref.split(',');
        const baseRef = parts[0];
        const relayHints = parts.slice(1).filter(r => r.startsWith('wss://'));
        
        const [kindStr, pubkey, dTag] = baseRef.split(':');
        const kind = parseInt(kindStr);
        
        console.log(`Fetching ${kind} event with d-tag ${dTag} from author ${pubkey}`);
        
        // Temporarily add these relays to NDK for this specific fetch
        if (relayHints.length > 0) {
          console.log(`With relay hints: ${relayHints.join(', ')}`);
          
          for (const relay of relayHints) {
            try {
              this.safeAddRelay(ndk, relay);
              addedRelays.add(relay);
            } catch (err) {
              console.warn(`Failed to add relay ${relay}:`, err);
            }
          }
        }
        
        // Create a filter to find this specific event
        const filter: NDKFilter = {
          kinds: [kind],
          authors: [pubkey],
          '#d': [dTag]
        };
        
        // Try to fetch by filter first
        const fetchedEvents = await ndk.fetchEvents(filter);
        
        if (fetchedEvents.size > 0) {
          const event = Array.from(fetchedEvents)[0];
          
          // Add the relay hints to the event for future reference
          if (relayHints.length > 0) {
            relayHints.forEach(relay => {
              // Check if the relay is already in tags
              const existingRelayTag = event.getMatchingTags('r').some(tag => 
                tag.length > 1 && tag[1] === relay
              );
              
              if (!existingRelayTag) {
                event.tags.push(['r', relay]);
              }
            });
          }
          
          events.push(event);
          continue;
        }
        
        // If not found by d-tag, try to fetch by ID directly
        console.log(`Trying to fetch event directly by ID: ${dTag}`);
        try {
          const event = await ndk.fetchEvent(dTag);
          if (event) {
            console.log(`Successfully fetched event by ID: ${dTag}`);
            
            // Add the relay hints to the event for future reference
            if (relayHints.length > 0) {
              relayHints.forEach(relay => {
                // Check if the relay is already in tags
                const existingRelayTag = event.getMatchingTags('r').some(tag => 
                  tag.length > 1 && tag[1] === relay
                );
                
                if (!existingRelayTag) {
                  event.tags.push(['r', relay]);
                }
              });
            }
            
            events.push(event);
          }
        } catch (idError) {
          console.error(`Error fetching by ID: ${idError}`);
        }
      } catch (error) {
        console.error(`Error fetching reference ${ref}:`, error);
      }
    }
    
    // Clean up - remove any temporarily added relays
    if (addedRelays.size > 0) {
      console.log(`Removing ${addedRelays.size} temporarily added relays`);
      for (const relay of addedRelays) {
        try {
          this.safeRemoveRelay(ndk, relay);
        } catch (err) {
          console.warn(`Failed to remove relay ${relay}:`, err);
        }
      }
    }
    
    console.log(`Total fetched referenced events: ${events.length}`);
    return events;
  }
  
  /**
   * Analyze dependencies between templates and exercises
   */
  analyzeDependencies(templates: NDKEvent[], exercises: NDKEvent[]): Record<string, string[]> {
    const dependencies: Record<string, string[]> = {};
    const exerciseMap = new Map<string, NDKEvent>();
    const exerciseWithRelays = new Map<string, {event: NDKEvent, relays: string[]}>();
    
    // Map exercises by "kind:pubkey:d-tag" for easier lookup, preserving relay hints
    for (const exercise of exercises) {
      const dTag = exercise.tagValue('d');
      if (dTag) {
        const reference = `33401:${exercise.pubkey}:${dTag}`;
        exerciseMap.set(reference, exercise);
        
        // Extract relay hints from event if available
        const relays: string[] = [];
        exercise.getMatchingTags('r').forEach(tag => {
          if (tag.length > 1 && tag[1].startsWith('wss://')) {
            relays.push(tag[1]);
          }
        });
        
        // Store event with its relay hints
        exerciseWithRelays.set(reference, {event: exercise, relays});
        
        console.log(`Mapped exercise ${exercise.id} to reference ${reference} with ${relays.length} relay hints`);
      }
    }
    
    // Analyze each template for its exercise dependencies
    for (const template of templates) {
      const templateId = template.id;
      const templateName = template.tagValue('title') || 'Unnamed Template';
      
      console.log(`Analyzing template ${templateName} (${templateId})`);
      dependencies[templateId] = [];
      
      // Get exercise references from template
      const exerciseTags = template.getMatchingTags('exercise');
      
      for (const tag of exerciseTags) {
        if (tag.length < 2) continue;
        
        // Parse the full reference with potential relay hints
        const fullRef = tag[1];
        
        // Split the reference to handle parameters first
        const refWithParams = fullRef.split(',')[0]; // Get reference part without relay hints
        const baseRef = refWithParams.split('::')[0]; // Extract base reference without parameters
        
        // Extract relay hints from the comma-separated list
        const relayHintsFromCommas = fullRef.split(',').slice(1).filter(r => r.startsWith('wss://'));
        
        // Also check for relay hints in additional tag elements
        const relayHintsFromTag = tag.slice(2).filter(item => item.startsWith('wss://'));
        
        // Combine all relay hints
        const relayHints = [...relayHintsFromCommas, ...relayHintsFromTag];
        
        console.log(`Template ${templateName} references ${refWithParams} with ${relayHints.length} relay hints`);
        
        // Find the exercise in our mapped exercises using only the base reference
        const exercise = exerciseMap.get(baseRef);
        if (exercise) {
          dependencies[templateId].push(exercise.id);
          
          // Add any relay hints to our stored exercise data
          const existingData = exerciseWithRelays.get(baseRef);
          if (existingData && relayHints.length > 0) {
            // Merge relay hints without duplicates
            const uniqueRelays = new Set([...existingData.relays, ...relayHints]);
            exerciseWithRelays.set(baseRef, {
              event: existingData.event,
              relays: Array.from(uniqueRelays)
            });
            
            console.log(`Updated relay hints for ${baseRef}: ${Array.from(uniqueRelays).join(', ')}`);
          }
          
          console.log(`Template ${templateName} depends on exercise ${exercise.id}`);
        } else {
          console.log(`Template ${templateName} references unknown exercise ${refWithParams}`);
        }
      }
      
      console.log(`Template ${templateName} has ${dependencies[templateId].length} dependencies`);
    }
    
    // Store the enhanced exercise mapping with relay hints in a class property
    this.exerciseWithRelays = exerciseWithRelays;
    
    return dependencies;
  }

  // Inside your POWRPackService class
  private safeAddRelay(ndk: NDK, url: string): void {
    try {
      // Direct property access to check if method exists
      if (typeof (ndk as any).addRelay === 'function') {
        (ndk as any).addRelay(url);
        console.log(`Added relay: ${url}`);
      } else {
        // Fallback implementation using pool
        if (ndk.pool && ndk.pool.relays) {
          const relay = ndk.pool.getRelay?.(url);
          if (!relay) {
            console.log(`Could not add relay ${url} - no implementation available`);
          }
        }
      }
    } catch (error) {
      console.warn(`Failed to add relay ${url}:`, error);
    }
  }
  
  private safeRemoveRelay(ndk: NDK, url: string): void {
    try {
      // Direct property access to check if method exists
      if (typeof (ndk as any).removeRelay === 'function') {
        (ndk as any).removeRelay(url);
        console.log(`Removed relay: ${url}`);
      } else {
        // Fallback implementation using pool
        if (ndk.pool && ndk.pool.relays) {
          ndk.pool.relays.delete(url);
          console.log(`Removed relay ${url} using pool.relays.delete`);
        }
      }
    } catch (error) {
      console.warn(`Failed to remove relay ${url}:`, error);
    }
  }
  
  /**
   * Import a POWR Pack into the local database
   */
  async importPack(packImport: POWRPackImport, selection: POWRPackSelection): Promise<void> {
    try {
      console.log(`=== STARTING PACK IMPORT ===`);
      console.log(`Importing ${selection.selectedExercises.length} exercises and ${selection.selectedTemplates.length} templates...`);
      
      // Map to track imported exercise IDs by various reference formats
      const exerciseIdMap = new Map<string, string>();
      
      // First, import the selected exercises
      for (const exerciseId of selection.selectedExercises) {
        const exerciseEvent = packImport.exercises.find(e => e.id === exerciseId);
        if (!exerciseEvent) {
          console.log(`Exercise event ${exerciseId} not found in pack data`);
          continue;
        }
        
        // Get the d-tag value from the event
        const dTag = exerciseEvent.tagValue('d');
        
        // Convert to local model
        const exerciseModel = this.nostrIntegration.convertNostrExerciseToLocal(exerciseEvent);
        
        // Save to database
        const localId = await this.nostrIntegration.saveImportedExercise(exerciseModel, exerciseEvent);
        
        // Map ALL possible ways to reference this exercise:
        
        // 1. By event ID directly (fallback)
        exerciseIdMap.set(exerciseId, localId);
        
        // 2. By standard d-tag reference format (if d-tag exists)
        if (dTag) {
          const dTagRef = `33401:${exerciseEvent.pubkey}:${dTag}`;
          exerciseIdMap.set(dTagRef, localId);
          console.log(`Mapped d-tag reference ${dTagRef} to local exercise ID ${localId}`);
        }
        
        // 3. By event ID as d-tag (for templates that reference this way)
        const eventIdRef = `33401:${exerciseEvent.pubkey}:${exerciseId}`;
        exerciseIdMap.set(eventIdRef, localId);
        console.log(`Mapped event ID reference ${eventIdRef} to local exercise ID ${localId}`);
        
        console.log(`Imported exercise: ${exerciseModel.title} (${localId}) from Nostr event ${exerciseId}`);
      }
      
      console.log(`=== EXERCISE IMPORT COMPLETE ===`);
      console.log(`Total exercise reference mappings: ${exerciseIdMap.size}`);
      console.log(`Now importing ${selection.selectedTemplates.length} templates...`);
      
      // Then, import the selected templates
      for (const templateId of selection.selectedTemplates) {
        const templateEvent = packImport.templates.find(t => t.id === templateId);
        if (!templateEvent) {
          console.log(`Template event ${templateId} not found in pack data`);
          continue;
        }
        
        // Convert to local model
        const templateModel = this.nostrIntegration.convertNostrTemplateToLocal(templateEvent);
        
        // Save to database
        const localTemplateId = await this.nostrIntegration.saveImportedTemplate(templateModel, templateEvent);
        
        console.log(`Imported template: ${templateModel.title} (${localTemplateId}) from Nostr event ${templateId}`);
        
        // Get exercise references from this template
        const exerciseRefs = this.nostrIntegration.getTemplateExerciseRefs(templateEvent);
        
        console.log(`Template has ${exerciseRefs.length} exercise references:`);
        exerciseRefs.forEach(ref => console.log(`  - ${ref}`));
        
        // Map exercise references to local exercise IDs
        const templateExerciseIds: string[] = [];
        const matchedRefs: string[] = [];
        
        console.log(`=== DEBUG: Template ID Mapping Process ===`);
        console.log(`Template Event: ${templateEvent.id}`);
        console.log(`Template Local ID: ${localTemplateId}`);
        
        for (const ref of exerciseRefs) {
          // Extract the base reference (before any parameters)
          const refParts = ref.split('::');
          const baseRefWithRelays = refParts[0]; // May include relay hints separated by commas
          const parts = baseRefWithRelays.split(',');
          const baseRef = parts[0]; // Just the kind:pubkey:d-tag part
          
          console.log(`Looking for matching exercise for reference: ${baseRef}`);
          
          // Check if we have this reference in our map
          if (exerciseIdMap.has(baseRef)) {
            const localExerciseId = exerciseIdMap.get(baseRef) || '';
            templateExerciseIds.push(localExerciseId);
            matchedRefs.push(ref);
            
            console.log(`✅ Direct match found! Mapped reference ${baseRef} to local exercise ID ${localExerciseId}`);
            continue;
          }
          
          // If not found by direct reference, try to match by examining individual components
          console.log(`⚠️ No direct match for reference: ${baseRef}. Trying to match by components...`);
          
          // Parse the reference for fallback matching
          const refSegments = baseRef.split(':');
          if (refSegments.length >= 3) {
            const refKind = refSegments[0];
            const refPubkey = refSegments[1];
            const refDTag = refSegments[2];
            
            // Log all entries in exerciseIdMap for debugging
            console.log(`Looking among ${exerciseIdMap.size} existing mappings:`);
            [...exerciseIdMap.entries()].forEach(([key, value]) => {
              console.log(`  - ${key} -> ${value}`);
            });
            
            // Try to find the matching exercise by direct dTag match
            const directDTagMatch = [...exerciseIdMap.entries()].find(([key, _]) => {
              return key.includes(refPubkey) && key.includes(refDTag);
            });
            
            if (directDTagMatch) {
              const [matchKey, matchValue] = directDTagMatch;
              templateExerciseIds.push(matchValue);
              matchedRefs.push(ref);
              
              // Also add this reference format to map for future lookups
              exerciseIdMap.set(baseRef, matchValue);
              
              console.log(`✅ Found match by dTag: ${matchKey} -> ${matchValue}`);
              continue;
            }
            
            // Try to find the matching exercise by event ID
            const matchingEvent = packImport.exercises.find(e => e.id === refDTag);
            
            if (matchingEvent && exerciseIdMap.has(matchingEvent.id)) {
              const localExerciseId = exerciseIdMap.get(matchingEvent.id) || '';
              templateExerciseIds.push(localExerciseId);
              matchedRefs.push(ref);
              
              // Add this reference to our map for future use
              exerciseIdMap.set(baseRef, localExerciseId);
              
              console.log(`✅ Found match by event ID: ${matchingEvent.id} -> ${localExerciseId}`);
              continue;
            }
            
            console.log(`❌ No matching exercise found for reference: ${baseRef}`);
          } else {
            console.log(`❌ Invalid reference format: ${baseRef}`);
          }
        }
        
        console.log(`Mapped ${templateExerciseIds.length}/${exerciseRefs.length} references for template ${templateModel.title}`);
        console.log(`=== END DEBUG ===`);
        
        // Save template-exercise relationships with parameters
        if (templateExerciseIds.length > 0) {
          await this.nostrIntegration.saveTemplateExercisesWithParams(
            localTemplateId, 
            templateExerciseIds, 
            matchedRefs
          );
          
          // Log the result 
          console.log(`Checking saved template: ${localTemplateId}`);
          const templateExercises = await this.db.getAllAsync<{ exercise_id: string }>(
            `SELECT exercise_id FROM template_exercises WHERE template_id = ?`,
            [localTemplateId]
          );
          console.log(`Template ${templateModel.title} has ${templateExercises.length} exercises associated`);
        } else {
          console.log(`⚠️ No exercise relationships to save for template ${localTemplateId}`);
        }
      }
      
      // Finally, save the pack itself
      await this.savePack(packImport.packEvent, selection);

      // Trigger refresh of templates and exercises
      useLibraryStore.getState().refreshTemplates();
      useLibraryStore.getState().refreshExercises();
      useLibraryStore.getState().refreshPacks();
      
      // Get total counts
      const totalNostrTemplates = await this.db.getFirstAsync<{ count: number }>(
        `SELECT COUNT(*) as count FROM templates WHERE source = 'nostr'`
      );
      
      console.log(`Total nostr templates in database: ${totalNostrTemplates?.count || 0}`);
      
      // Get imported template IDs for verification
      const templates = await this.db.getAllAsync<{ id: string, title: string }>(
        `SELECT id, title FROM templates WHERE source = 'nostr'`
      );
      
      console.log(`Imported Template IDs:`);
      templates.forEach(t => {
        console.log(`  - ${t.title}: ${t.id}`);
      });
      
      // Verify template-exercise relationships
      for (const template of templates) {
        const relationships = await this.db.getAllAsync<{ count: number }>(
          `SELECT COUNT(*) as count FROM template_exercises WHERE template_id = ?`,
          [template.id]
        );
        console.log(`Template ${template.title}: ${relationships[0]?.count || 0} exercises`);
      }
      
      console.log(`=== PACK IMPORT COMPLETE ===`);
    } catch (error) {
      console.error('Error importing pack:', error);
      throw error;
    }
  }
  
  /**
   * Save the pack metadata to the database
   */
  private async savePack(packEvent: NDKEvent, selection: POWRPackSelection): Promise<string> {
    try {
      const now = Date.now();
      
      // Get pack metadata
      const title = packEvent.tagValue('name') || 'Unnamed Pack';
      const description = packEvent.tagValue('about') || packEvent.content || '';
      
      // Save pack to database
      await this.db.runAsync(
        `INSERT INTO powr_packs (id, title, description, author_pubkey, nostr_event_id, import_date, updated_at)
         VALUES (?, ?, ?, ?, ?, ?, ?)`,
        [
          selection.packId,
          title,
          description,
          packEvent.pubkey,
          packEvent.id,
          now,
          now
        ]
      );
      
      // Save pack items (templates and exercises)
      let order = 0;
      
      // Save template items
      for (const templateId of selection.selectedTemplates) {
        await this.db.runAsync(
          `INSERT INTO powr_pack_items (pack_id, item_id, item_type, item_order, is_imported, nostr_event_id)
           VALUES (?, ?, ?, ?, ?, ?)`,
          [
            selection.packId,
            templateId,
            'template',
            order++,
            1, // Imported
            templateId
          ]
        );
      }
      
      // Save exercise items
      for (const exerciseId of selection.selectedExercises) {
        await this.db.runAsync(
          `INSERT INTO powr_pack_items (pack_id, item_id, item_type, item_order, is_imported, nostr_event_id)
           VALUES (?, ?, ?, ?, ?, ?)`,
          [
            selection.packId,
            exerciseId,
            'exercise',
            order++,
            1, // Imported
            exerciseId
          ]
        );
      }
      
      return selection.packId;
    } catch (error) {
      console.error('Error saving pack:', error);
      throw error;
    }
  }
  
  /**
 * Get all imported packs
 */
  async getImportedPacks(): Promise<POWRPackWithContent[]> {
    try {
      // Get all packs
      const packs = await this.db.getAllAsync<{
        id: string;
        title: string;
        description: string;
        author_pubkey: string;
        nostr_event_id: string;
        import_date: number;
        updated_at: number;
      }>(
        `SELECT * FROM powr_packs ORDER BY import_date DESC`
      );
      
      // For each pack, get its templates and exercises
      const result: POWRPackWithContent[] = [];
      
      for (const dbPack of packs) {
        // Transform to match POWRPack type
        const pack: POWRPack = {
          id: dbPack.id,
          title: dbPack.title,
          description: dbPack.description || '',
          authorPubkey: dbPack.author_pubkey,
          nostrEventId: dbPack.nostr_event_id,
          importDate: dbPack.import_date,
          updatedAt: dbPack.updated_at
        };
        
        // Get templates
        const templateData = await this.db.getAllAsync<{
          id: string;
          title: string;
          type: string;
          description: string;
          created_at: number;
        }>(
          `SELECT t.id, t.title, t.type, t.description, t.created_at
          FROM templates t
          JOIN powr_pack_items ppi ON ppi.item_id = t.nostr_event_id
          WHERE ppi.pack_id = ? AND ppi.item_type = 'template'
          ORDER BY ppi.item_order`,
          [pack.id]
        );
        
        // Transform template data to match WorkoutTemplate type
        const templates: WorkoutTemplate[] = templateData.map(t => ({
          id: t.id,
          title: t.title,
          type: (t.type || 'strength') as TemplateType,
          category: 'Custom', // Default value
          description: t.description,
          exercises: [], // Default empty array
          isPublic: true, // Default value
          version: 1, // Default value
          tags: [], // Default empty array
          created_at: t.created_at,
          availability: {
            source: ['nostr']
          }
        }));
        
        // Get exercises
        const exerciseData = await this.db.getAllAsync<{
          id: string;
          title: string;
          type: string;
          category: string;
          description: string;
          created_at: number;
        }>(
          `SELECT e.id, e.title, e.type, e.category, e.description, e.created_at
          FROM exercises e
          JOIN powr_pack_items ppi ON ppi.item_id = e.nostr_event_id
          WHERE ppi.pack_id = ? AND ppi.item_type = 'exercise'
          ORDER BY ppi.item_order`,
          [pack.id]
        );
        
        // Transform exercise data to match BaseExercise type
        const exercises: BaseExercise[] = exerciseData.map(e => ({
          id: e.id,
          title: e.title,
          type: e.type as ExerciseType,
          category: e.category as ExerciseCategory,
          description: e.description,
          tags: [], // Default empty array
          format: {}, // Default empty object
          format_units: {}, // Default empty object
          created_at: e.created_at,
          availability: {
            source: ['nostr']
          }
        }));
        
        result.push({
          pack,
          templates,
          exercises
        });
      }
      
      return result;
    } catch (error) {
      console.error('Error getting imported packs:', error);
      return [];
    }
  }

    /**
   * Create a shareable naddr for a POWR Pack
   * @param packEvent The Nostr event for the pack
   * @returns A shareable naddr string
   */
  createShareableNaddr(packEvent: NDKEvent): string {
    try {
      // Extract d-tag for the pack (required for naddr)
      const dTag = packEvent.tagValue('d');
      
      if (!dTag) {
        throw new Error('Pack event missing required d-tag');
      }
      
      // Create naddr using NDK's methods
      const naddr = packEvent.encode();
      return naddr;
    } catch (error) {
      console.error('Error creating shareable naddr:', error);
      
      // Fallback: manually construct naddr if NDK's encode fails
      try {
        const { nip19 } = require('nostr-tools');
        
        const dTag = packEvent.tagValue('d') || '';
        
        return nip19.naddrEncode({
          kind: packEvent.kind,
          pubkey: packEvent.pubkey,
          identifier: dTag,
          relays: [] // Optional relay hints
        });
      } catch (fallbackError) {
        console.error('Fallback naddr creation failed:', fallbackError);
        throw new Error('Could not create shareable link for pack');
      }
    }
  }

  /**
   * Delete a POWR Pack and all its associated content
   * @param packId The ID of the pack to delete
   * @param keepItems DEPRECATED parameter kept for backward compatibility
   */
  async deletePack(packId: string, keepItems: boolean = false): Promise<void> {
    try {
      console.log(`[POWRPackService] Starting deletion of pack ${packId}`);
      
      // Always delete everything, ignore keepItems parameter
      await this.db.withTransactionAsync(async () => {
        // First, get all templates and exercises from this pack
        console.log(`[POWRPackService] Finding templates associated with pack ${packId}`);
        const templates = await this.db.getAllAsync<{ id: string, nostr_event_id: string }>(
          `SELECT t.id, t.nostr_event_id
          FROM templates t
          JOIN powr_pack_items ppi ON ppi.item_id = t.nostr_event_id
          WHERE ppi.pack_id = ? AND ppi.item_type = 'template'`,
          [packId]
        );
        console.log(`[POWRPackService] Found ${templates.length} templates to delete`);
        
        console.log(`[POWRPackService] Finding exercises associated with pack ${packId}`);
        const exercises = await this.db.getAllAsync<{ id: string, nostr_event_id: string }>(
          `SELECT e.id, e.nostr_event_id
          FROM exercises e
          JOIN powr_pack_items ppi ON ppi.item_id = e.nostr_event_id
          WHERE ppi.pack_id = ? AND ppi.item_type = 'exercise'`,
          [packId]
        );
        console.log(`[POWRPackService] Found ${exercises.length} exercises to delete`);
        
        // Find any additional exercises that are only referenced by templates in this pack
        console.log(`[POWRPackService] Finding template exercises`);
        const templateIds = templates.map(t => t.id);
        let additionalExerciseIds: string[] = [];
        
        if (templateIds.length > 0) {
          const templateExercises = await this.db.getAllAsync<{ exercise_id: string }>(
            `SELECT DISTINCT exercise_id 
            FROM template_exercises 
            WHERE template_id IN (${templateIds.map(() => '?').join(',')})`,
            templateIds
          );
          
          additionalExerciseIds = templateExercises.map(te => te.exercise_id);
          console.log(`[POWRPackService] Found ${additionalExerciseIds.length} additional exercises from templates`);
        }
        
        // Delete the templates and their exercises
        for (const template of templates) {
          console.log(`[POWRPackService] Deleting template ${template.id}`);
          
          // Delete template exercises first
          await this.db.runAsync(
            `DELETE FROM template_exercises WHERE template_id = ?`,
            [template.id]
          );
          
          // Then delete the template
          await this.db.runAsync(
            `DELETE FROM templates WHERE id = ?`,
            [template.id]
          );
        }
        
        // Build a set of all exercise IDs to delete
        const exerciseIdsToDelete = new Set([
          ...exercises.map(e => e.id),
          ...additionalExerciseIds
        ]);
        
        // Delete the exercises
        for (const exerciseId of exerciseIdsToDelete) {
          console.log(`[POWRPackService] Deleting exercise ${exerciseId}`);
          
          // Delete exercise tags first
          await this.db.runAsync(
            `DELETE FROM exercise_tags WHERE exercise_id = ?`,
            [exerciseId]
          );
          
          // Then delete the exercise
          await this.db.runAsync(
            `DELETE FROM exercises WHERE id = ?`,
            [exerciseId]
          );
        }
        
        // Delete the pack items
        console.log(`[POWRPackService] Deleting pack items for pack ${packId}`);
        await this.db.runAsync(
          `DELETE FROM powr_pack_items WHERE pack_id = ?`,
          [packId]
        );
        
        // Finally, delete the pack itself
        console.log(`[POWRPackService] Deleting pack ${packId}`);
        await this.db.runAsync(
          `DELETE FROM powr_packs WHERE id = ?`,
          [packId]
        );
        
        // Trigger refresh of templates and exercises
        useLibraryStore.getState().refreshTemplates();
        useLibraryStore.getState().refreshExercises();
        useLibraryStore.getState().refreshPacks();
        // Clear any cached data
        useLibraryStore.getState().clearCache();
        
        console.log(`[POWRPackService] Successfully deleted pack ${packId} with ${templates.length} templates and ${exerciseIdsToDelete.size} exercises`);
      });
    } catch (error) {
      console.error(`[POWRPackService] Error deleting pack ${packId}:`, error);
      throw error;
    }
  }
}