// lib/services/NostrWorkoutService.ts
import { Workout, WorkoutExercise, WorkoutSet } from '@/types/workout';
import { WorkoutTemplate, TemplateExerciseConfig } from '@/types/templates';
import { NostrEvent } from '@/types/nostr';
import { generateId } from '@/utils/ids';
import { ExerciseCategory, ExerciseType } from '@/types/exercise';
import { TemplateType } from '@/types/templates';
/**
 * Service for creating and handling Nostr workout events
 */
export class NostrWorkoutService {
  /**
   * Creates a complete Nostr workout event with all details
   */
  static createCompleteWorkoutEvent(workout: Workout): NostrEvent {
    return this.workoutToNostrEvent(workout, false);
  }

  /**
   * Creates a limited Nostr workout event with reduced metrics for privacy
   */
  static createLimitedWorkoutEvent(workout: Workout): NostrEvent {
    return this.workoutToNostrEvent(workout, true);
  }

  /**
   * Creates a social share event that quotes the workout record
   */
  static createSocialShareEvent(workoutEventId: string, message: string): NostrEvent {
    return this.createShareEvent(workoutEventId, '1301', message);
  }

  /**
   * Creates a social share event that quotes a POWR event
   * @param eventId The ID of the event being quoted
   * @param kind The kind number of the event being quoted (1301, 33401, 33402)
   * @param message The message content for the social post
   * @param additionalTags Optional additional tags to include
   */
  static createShareEvent(
    eventId: string, 
    kind: '1301' | '33401' | '33402', 
    message: string,
    additionalTags: string[][] = []
  ): NostrEvent {
    // Determine appropriate hashtags based on kind
    const contentTypeTags: string[][] = [];
    
    if (kind === '1301') {
      contentTypeTags.push(['t', 'workout']);
    } else if (kind === '33401') {
      contentTypeTags.push(['t', 'exercise']);
    } else if (kind === '33402') {
      contentTypeTags.push(['t', 'workouttemplate']);
    }
    
    return {
      kind: 1,
      content: message,
      tags: [
        // Quote the event
        ['q', eventId],
        // Add kind tag
        ['k', kind],
        // Add standard fitness tag
        ['t', 'fitness'],
        // Add content-specific tags
        ...contentTypeTags,
        // Add any additional tags
        ...additionalTags
      ],
      created_at: Math.floor(Date.now() / 1000)
    };
  }

  /**
   * Generic method to convert a workout to a Nostr event
   * @param workout The workout data
   * @param isLimited Whether to include limited data only
   * @returns A NostrEvent (kind 1301)
   */
  static workoutToNostrEvent(workout: Workout, isLimited: boolean = false): NostrEvent {
    // Format start and end dates as Unix timestamps in seconds
    const startTime = Math.floor(workout.startTime / 1000);
    const endTime = workout.endTime ? Math.floor(workout.endTime / 1000) : undefined;
    
    // Prepare tags for Nostr event
    const tags: string[][] = [
      ["d", workout.id],
      ["title", workout.title],
      ["type", workout.type],
      ["start", startTime.toString()],
      ["end", endTime ? endTime.toString() : ""],
      ["completed", workout.isCompleted ? "true" : "false"]
    ];
    
    // Add template reference if available
    if (workout.templateId) {
      tags.push(["template", `33402:${workout.templatePubkey || ''}:${workout.templateId}`, ""]);
    }
    
    // Add exercise data
    if (isLimited) {
      // Limited data - just exercise names without metrics
      workout.exercises.forEach(exercise => {
        tags.push(["exercise", `33401:${exercise.exerciseId || exercise.id}`]);
      });
    } else {
      // Full data - include all metrics
      workout.exercises.forEach(exercise => 
        exercise.sets.forEach(set => {
          const exerciseTag = [
            "exercise",
            `33401:${exercise.exerciseId || exercise.id}`,
            ""
          ];
          
          // Add set data
          if (set.weight !== undefined) exerciseTag.push(set.weight.toString());
          if (set.reps !== undefined) exerciseTag.push(set.reps.toString());
          if (set.rpe !== undefined) exerciseTag.push(set.rpe.toString());
          if (set.type) exerciseTag.push(set.type);
          
          tags.push(exerciseTag);
        })
      );
    }
    
    // Add any workout tags
    workout.tags?.forEach(tag => {
      tags.push(["t", tag]);
    });
    
    return {
      kind: 1301,
      content: workout.notes || "",
      created_at: Math.floor(Date.now() / 1000),
      tags
    };
  }

  /**
   * Convert a Nostr event to a workout
   */
  static nostrEventToWorkout(event: NostrEvent): Workout {
    if (event.kind !== 1301) {
      throw new Error('Event is not a workout record (kind 1301)');
    }
    
    // Find tag values
    const findTagValue = (name: string): string | null => {
      const tag = event.tags.find(t => t[0] === name);
      return tag && tag.length > 1 ? tag[1] : null;
    };
    
    // Parse dates
    const startTimeStr = findTagValue('start');
    const endTimeStr = findTagValue('end');
    
    const startTime = startTimeStr ? parseInt(startTimeStr) * 1000 : Date.now();
    const endTime = endTimeStr && endTimeStr !== '' ? parseInt(endTimeStr) * 1000 : undefined;
    
    // Create base workout object
    const workout: Partial<Workout> = {
      id: findTagValue('d') || generateId('nostr'),
      title: findTagValue('title') || 'Untitled Workout',
      type: (findTagValue('type') || 'strength') as TemplateType,
      startTime,
      endTime,
      isCompleted: findTagValue('completed') === 'true',
      notes: event.content,
      created_at: event.created_at * 1000,
      lastUpdated: Date.now(),
      nostrEventId: event.id,
      availability: { source: ['nostr'] },
      exercises: [],
      shareStatus: 'public'
    };
    
    // Parse template reference
    const templateTag = event.tags.find(t => t[0] === 'template');
    if (templateTag && templateTag.length > 1) {
      const parts = templateTag[1].split(':');
      if (parts.length === 3) {
        workout.templateId = parts[2];
        workout.templatePubkey = parts[1];
      }
    }
    
    // Parse exercises and sets
    const exerciseTags = event.tags.filter(t => t[0] === 'exercise');
    
    // Group exercise tags by exercise ID
    const exerciseMap = new Map<string, string[][]>();
    
    exerciseTags.forEach(tag => {
      if (tag.length < 2) return;
      
      const exerciseRef = tag[1];
      let exerciseId = exerciseRef;
      
      // Parse exercise ID from reference
      if (exerciseRef.includes(':')) {
        const parts = exerciseRef.split(':');
        if (parts.length === 3) {
          exerciseId = parts[2];
        }
      }
      
      if (!exerciseMap.has(exerciseId)) {
        exerciseMap.set(exerciseId, []);
      }
      
      exerciseMap.get(exerciseId)?.push(tag);
    });
    
    // Convert each unique exercise to a WorkoutExercise
    workout.exercises = Array.from(exerciseMap.entries()).map(([exerciseId, tags]) => {
      // Create a basic exercise
      const exercise: Partial<WorkoutExercise> = {
        id: generateId('nostr'),
        exerciseId: exerciseId,
        title: `Exercise ${exerciseId}`, // Placeholder - would be updated when loading full details
        type: 'strength' as ExerciseType,
        category: 'Other' as ExerciseCategory, // Default
        created_at: workout.created_at || Date.now(),
        lastUpdated: workout.lastUpdated,
        isCompleted: true, // Default for past workouts
        availability: { source: ['nostr'] },
        tags: [], // Add empty tags array
        sets: []
      };
      
      // Parse sets from tags
      exercise.sets = tags.map(tag => {
        const set: Partial<WorkoutSet> = {
          id: generateId('nostr'),
          type: 'normal',
          isCompleted: true,
          lastUpdated: workout.lastUpdated
        };
        
        // Extract set data if available (weight, reps, rpe, type)
        if (tag.length > 3) set.weight = parseFloat(tag[3]) || undefined;
        if (tag.length > 4) set.reps = parseInt(tag[4]) || undefined;
        if (tag.length > 5) set.rpe = parseFloat(tag[5]) || undefined;
        if (tag.length > 6) set.type = tag[6] as any;
        
        return set as WorkoutSet;
      });
      
      // If no sets were found, add a default one
      if (exercise.sets.length === 0) {
        exercise.sets.push({
          id: generateId('nostr'),
          type: 'normal',
          isCompleted: true,
          lastUpdated: workout.lastUpdated
        });
      }
      
      return exercise as WorkoutExercise;
    });
    
    return workout as Workout;
  }

  /**
   * Convert a template to a Nostr event (kind 33402)
   */
  static templateToNostrEvent(template: WorkoutTemplate): NostrEvent {
    // Prepare tags for Nostr event
    const tags: string[][] = [
      ["d", template.id],
      ["title", template.title],
      ["type", template.type || "strength"]
    ];
    
    // Add optional tags
    if (template.rounds) {
      tags.push(["rounds", template.rounds.toString()]);
    }
    
    if (template.duration) {
      tags.push(["duration", template.duration.toString()]);
    }
    
    if (template.interval) {
      tags.push(["interval", template.interval.toString()]);
    }
    
    if (template.restBetweenRounds) {
      tags.push(["rest_between_rounds", template.restBetweenRounds.toString()]);
    }
    
    // Add exercise configurations
    template.exercises.forEach(ex => {
      const exerciseTag = [
        "exercise",
        `33401:${ex.exercise.id}`,
        ""
      ];
      
      // Add target parameters if available
      if (ex.targetSets) exerciseTag.push(ex.targetSets.toString());
      if (ex.targetReps) exerciseTag.push(ex.targetReps.toString());
      if (ex.targetWeight) exerciseTag.push(ex.targetWeight.toString());
      
      tags.push(exerciseTag);
    });
    
    // Add any template tags
    template.tags?.forEach(tag => {
      tags.push(["t", tag]);
    });
    
    return {
      kind: 33402,
      content: template.description || "",
      created_at: Math.floor(Date.now() / 1000),
      tags
    };
  }

  /**
   * Convert a Nostr event to a template
   */
  static nostrEventToTemplate(event: NostrEvent): WorkoutTemplate {
    if (event.kind !== 33402) {
      throw new Error('Event is not a workout template (kind 33402)');
    }
    
    // Find tag values
    const findTagValue = (name: string): string | null => {
      const tag = event.tags.find(t => t[0] === name);
      return tag && tag.length > 1 ? tag[1] : null;
    };
    
    // Create base template object
    const template: Partial<WorkoutTemplate> = {
      id: findTagValue('d') || generateId('nostr'),
      title: findTagValue('title') || 'Untitled Template',
      type: (findTagValue('type') || 'strength') as TemplateType,
      description: event.content,
      created_at: event.created_at * 1000,
      lastUpdated: Date.now(),
      nostrEventId: event.id,
      availability: { source: ['nostr'] },
      exercises: [],
      isPublic: true,
      version: 1,
      tags: []
    };
    
    // Parse optional parameters
    const roundsStr = findTagValue('rounds');
    if (roundsStr) template.rounds = parseInt(roundsStr);
    
    const durationStr = findTagValue('duration');
    if (durationStr) template.duration = parseInt(durationStr);
    
    const intervalStr = findTagValue('interval');
    if (intervalStr) template.interval = parseInt(intervalStr);
    
    const restStr = findTagValue('rest_between_rounds');
    if (restStr) template.restBetweenRounds = parseInt(restStr);
    
    // Parse exercises
    const exerciseTags = event.tags.filter(t => t[0] === 'exercise');
    
    template.exercises = exerciseTags.map(tag => {
      if (tag.length < 2) {
        // Skip invalid tags
        return null;
      }
      
      const exerciseRef = tag[1];
      let exerciseId = exerciseRef;
      let exercisePubkey = '';
      
      // Parse exercise ID from reference
      if (exerciseRef.includes(':')) {
        const parts = exerciseRef.split(':');
        if (parts.length === 3) {
          exerciseId = parts[2];
          exercisePubkey = parts[1];
        }
      }
      
      // Create exercise config
      const config: Partial<TemplateExerciseConfig> = {
        id: generateId('nostr'),
        exercise: {
          id: exerciseId,
          title: `Exercise ${exerciseId}`, // Placeholder - would be updated when loading full details
          type: 'strength',
          category: 'Other' as ExerciseCategory,
          tags: [], // Add empty tags array
          availability: { source: ['nostr'] },
          created_at: Date.now()
        }
      };
      
      // Parse target parameters if available
      if (tag.length > 3) config.targetSets = parseInt(tag[3]) || undefined;
      if (tag.length > 4) config.targetReps = parseInt(tag[4]) || undefined;
      if (tag.length > 5) config.targetWeight = parseFloat(tag[5]) || undefined;
      
      return config as TemplateExerciseConfig;
    }).filter(Boolean) as TemplateExerciseConfig[]; // Filter out null values
    
    return template as WorkoutTemplate;
  }

  /**
   * Helper function to find a tag value in a Nostr event
   */
  static findTagValue(tags: string[][], name: string): string | null {
    const tag = tags.find(t => t[0] === name);
    return tag && tag.length > 1 ? tag[1] : null;
  }
  
  /**
   * Helper function to get all values for a specific tag name
   */
  static getTagValues(tags: string[][], name: string): string[] {
    return tags.filter(t => t[0] === name).map(t => t[1]);
  }
  
  /**
   * Helper function to get template tag information
   */
  static getTemplateTag(tags: string[][]): { reference: string, relay: string } | undefined {
    const templateTag = tags.find(t => t[0] === 'template');
    if (!templateTag || templateTag.length < 3) return undefined;
    
    return {
      reference: templateTag[1],
      relay: templateTag[2] || ''
    };
  }
}