import { WorkoutSession, UserProfile, WorkoutPlan } from '../types';
import { api } from './api';
import { generateId } from '../utils/uuid';
import { t } from './i18n';

interface ApiResponse<T> {
  success: boolean;
  data: T;
  error?: string;
}

interface FitnessChatOptions {
  history: WorkoutSession[];
  userProfile?: UserProfile;
  plans?: WorkoutPlan[];
  lang?: 'en' | 'ru';
  sessionId?: string;
}

export const createFitnessChat = (
  history: WorkoutSession[],
  lang: 'en' | 'ru' = 'ru',
  userProfile?: UserProfile,
  plans?: WorkoutPlan[]
): any => {
  // Generate a unique session ID for this chat instance
  const sessionId = generateId();

  // Calculate personal records
  // Reuse the logic via shared helper if possible, or keep as is if we want to include 'plans'. 
  // The helper getUserContextString currently doesn't include 'plans', so we will use it for history/profile and append plans manually.

  const userContext = getUserContextString(history, userProfile, lang);

  // Build comprehensive system instruction
  const systemInstruction = lang === 'ru' ? `
    Ты — опытный и поддерживающий фитнес-тренер AI Coach. 
    Твоя задача — анализировать тренировки пользователя и давать краткие, полезные советы на русском языке.
    
    ${userContext}
    
    ТРЕНИРОВОЧНЫЕ ПЛАНЫ:
    ${plans && plans.length > 0 ? JSON.stringify(plans.map(p => ({ name: p.name, exercises: p.steps.map(s => s.exerciseName) }))) : 'Нет активных планов'}
    
    ИНСТРУКЦИИ:
    - Используй эти данные для анализа прогресса и ответов на вопросы
    - Учитывай вес пользователя при анализе упражнений с собственным весом
    - Будь конкретным и ссылайся на реальные данные из истории
    - Отвечай емко, мотивирующе
    - Если данных недостаточно для ответа, честно скажи об этом
  ` : `
    You are an experienced and supportive fitness coach called AI Coach.
    Your task is to analyze the user's workouts and provide concise, helpful advice in English.
    
    ${userContext}
    
    WORKOUT PLANS:
    ${plans && plans.length > 0 ? JSON.stringify(plans.map(p => ({ name: p.name, exercises: p.steps.map(s => s.exerciseName) }))) : 'No active plans'}
    
    INSTRUCTIONS:
    - Use this data to analyze progress and answer questions
    - Consider user's weight when analyzing bodyweight exercises
    - Be specific and reference actual data from the history
    - Answer concisely and motivationally
    - If there's insufficient data to answer, be honest about it
    - ALWAYS answer in the language the user speaks to you
  `;

  return {
    sendMessage: async (userMessage: string) => {
      const res = await api.post<ApiResponse<{ response: string }>>('/ai/chat', {
        systemInstruction,
        userMessage,
        sessionId
      });
      return {
        text: res.data.response,
        response: {
          text: () => res.data.response
        }
      };
    }
  };
};


interface AIPlanExercise {
  name: string;
  isWeighted: boolean;
  restTimeSeconds: number;
  // For new exercises:
  type?: 'reps' | 'time';
  unilateral?: boolean;
}

interface AIPlanResponse {
  name: string;
  description: string;
  exercises: AIPlanExercise[];
}

// Removed duplicate import

// ... (other code)

// Helper to generate user context string
const getUserContextString = (history: WorkoutSession[], userProfile: UserProfile | undefined, lang: 'en' | 'ru') => {
  // Summarize workout history (Last 8 sessions)
  const workoutSummary = history.slice(0, 8).map(s => ({
    date: new Date(s.startTime).toLocaleDateString(lang === 'ru' ? 'ru-RU' : 'en-US'),
    planName: s.planName || (lang === 'ru' ? 'Свободная тренировка' : 'Freestyle'),
    exercises: s.sets.map(set => {
      const parts = [];
      parts.push(set.exerciseName);
      if (set.weight) parts.push(`${set.weight}${lang === 'ru' ? 'кг' : 'kg'}`);
      if (set.reps) parts.push(`${set.reps}${lang === 'ru' ? 'повт' : 'reps'}`);
      return parts.join(' ');
    }).join(', ')
  }));

  // Calculate personal records
  const exerciseRecords = new Map<string, { maxWeight?: number; maxReps?: number }>();
  history.forEach(session => {
    session.sets.forEach(set => {
      const current = exerciseRecords.get(set.exerciseName) || {};
      exerciseRecords.set(set.exerciseName, {
        maxWeight: Math.max(current.maxWeight || 0, set.weight || 0),
        maxReps: Math.max(current.maxReps || 0, set.reps || 0),
      });
    });
  });

  const personalRecords = Array.from(exerciseRecords.entries())
    .filter(([_, r]) => (r.maxWeight && r.maxWeight > 0) || (r.maxReps && r.maxReps > 10)) // Filter significant records
    .map(([name, records]) => ({
      exercise: name,
      ...records
    }));

  return lang === 'ru' ? `
    ПРОФИЛЬ ПОЛЬЗОВАТЕЛЯ:
    ${userProfile ? `
    - Вес: ${userProfile.weight || 'не указан'} кг
    - Рост: ${userProfile.height || 'не указан'} см
    - Пол: ${userProfile.gender || 'не указан'}
    ` : 'Профиль не заполнен'}
    
    ИСТОРИЯ (последние 8 тренировок):
    ${JSON.stringify(workoutSummary, null, 2)}
    
    ЛИЧНЫЕ РЕКОРДЫ:
    ${JSON.stringify(personalRecords, null, 2)}
  ` : `
    USER PROFILE:
    ${userProfile ? `
    - Weight: ${userProfile.weight || 'not specified'} kg
    - Height: ${userProfile.height || 'not specified'} cm
    - Gender: ${userProfile.gender || 'not specified'}
    ` : 'Profile not filled'}
    
    HISTORY (last 8 sessions):
    ${JSON.stringify(workoutSummary, null, 2)}
    
    PERSONAL RECORDS:
    ${JSON.stringify(personalRecords, null, 2)}
  `;
};

export const generateWorkoutPlan = async (
  userPrompt: string,
  availableExercises: string[],
  lang: 'en' | 'ru' = 'en',
  durationMinutes: number = 60,
  equipment: 'none' | 'essentials' | 'free_weights' | 'full_gym' = 'full_gym',
  level: 'beginner' | 'intermediate' | 'advanced' = 'intermediate',
  intensity: 'low' | 'moderate' | 'high' = 'moderate',
  history: WorkoutSession[] = [],
  userProfile?: UserProfile
): Promise<AIPlanResponse> => {
  const equipmentDescription = t(`ai_equipment_desc_${equipment}` as any, lang);
  const levelText = t(`level_${level}` as any, lang);
  const intensityText = t(`intensity_${intensity}` as any, lang);
  const userContext = getUserContextString(history, userProfile, lang);

  const durationText = durationMinutes >= 120
    ? (lang === 'ru' ? '2+ часа' : '2+ hours')
    : `${durationMinutes} ${lang === 'ru' ? 'минут' : 'minutes'}`;

  const systemInstruction = lang === 'ru'
    ? `Ты — генератор планов тренировок. Верни ТОЛЬКО JSON-объект.

${userContext}

ПАРАМЕТРЫ ПЛАНА:
- Длительность: ${durationText}
- Уровень: ${levelText}
- Интенсивность: ${intensityText}
- Оборудование: ${equipmentDescription}

ВАЖНО:
1. Используй историю тренировок и рекорды, чтобы подобрать подходящие веса (или указать их как ориентир в описании) и сложность.
2. Проанализируй последние тренировки, чтобы не перегружать недавно работавшие мышцы.
3. Каждый элемент массива exercises — это ОДИН подход. Если нужно 3 подхода одного упражнения, оно должно встретиться в списке 3 раза подряд.
4. Если план "Full Body" — задействуй ВСЕ крупные мышечные группы.

ПРАВИЛА НАЗВАНИЙ (ОЧЕНЬ ВАЖНО):
1. "Weighted" (с отягощением) — это параметр isWeighted: true, а БОЛЬШЕ НИКОГДА НЕ часть названия.
   - НЕЛЬЗЯ: "Weighted Pull-ups", "Подтягивания (с весом)"
   - ПРАВИЛЬНО: "Подтягивания" (isWeighted: true)
2. СТРОГО БЕЗ ВАРИАНТОВ ИЛИ ОПЦИЙ.
   - НЕЛЬЗЯ: "Отжимания (или на коленях)", "Ring Dips (or Barbell)"
   - ПРАВИЛЬНО: "Отжимания на кольцах"
3. СТРОГО БЕЗ ИНСТРУКЦИЙ ПО ТЕХНИКЕ И СКОБОК.
   - НЕЛЬЗЯ: "Подтягивания (до груди)", "Squats (ass to grass)"
   - ПРАВИЛЬНО: "Подтягивания", "Приседания"
4. Названия должны быть КОРОТКИМИ и ЧИСТЫМИ.

Формат ответа:
{
  "name": "Название плана",
  "description": "Описание/инструкции по подготовке (укажи, почему этот план подходит пользователю на основе его истории)",
  "exercises": [
    { "name": "Название упражнения", "isWeighted": false, "restTimeSeconds": 60 }
  ]
}
Если упражнение ОТСУТСТВУЕТ в списке доступных, добавь поля:
  "type": один из STRENGTH, BODYWEIGHT, CARDIO, STATIC, PLYOMETRIC,
  "unilateral": true или false

Доступные упражнения: ${JSON.stringify(availableExercises)}
`
    : `You are a workout plan generator. Return ONLY a JSON object.

${userContext}

WORKOUT PARAMETERS:
- Duration: ${durationText}
- Level: ${levelText}
- Intensity: ${intensityText}
- Equipment: ${equipmentDescription}

IMPORTANT:
1. Use workout history and records to adjust difficulty and suggest weights (in description).
2. Analyze recent sessions to avoid overworking recently trained muscles.
3. Each item in the exercises array represents ONE set. If you need 3 sets of an exercise, it must appear in the list 3 times consecutively.
4. "Full Body" means ALL big muscle groups must be involved.

EXTREMELY IMPORTANT NAMING RULES:
1. "Weighted" must be a parameter (isWeighted: true), NEVER part of the name.
   - BAD: "Weighted Pull-ups", "Pull-ups (Weighted)"
   - GOOD: "Pull-ups" (isWeighted: true)
2. STRICTLY NO VARIANTS OR ALTERNATIVES.
   - BAD: "Ring Dips (or Barbell Dips)", "Push-ups (or Kneeling)"
   - GOOD: "Ring Dips"
3. STRICTLY NO FORM NOTES OR PARENTHESES with instructions.
   - BAD: "Ring Rows (Chest to Rings)", "Squats (ass to grass)"
   - GOOD: "Ring Rows", "Squats"
4. Keep names CLEAN and SHORT.

Response format:
{
  "name": "Plan Name",
  "description": "Description/preparation instructions (explain why this fits based on user history)",
  "exercises": [
    { "name": "Exercise Name", "isWeighted": false, "restTimeSeconds": 60 }
  ]
}
If an exercise is NOT in the available list, also add:
  "type": one of STRENGTH, BODYWEIGHT, CARDIO, STATIC, PLYOMETRIC,
  "unilateral": true or false

Available exercises: ${JSON.stringify(availableExercises)}`;

  const res = await api.post<ApiResponse<{ response: string }>>('/ai/chat', {
    systemInstruction,
    userMessage: userPrompt,
    sessionId: generateId()
  });

  const responseText = res.data.response;

  // Try to parse JSON from the response
  // The AI might wrap it in ```json ... ``` or return raw JSON
  let jsonStr = responseText;
  const jsonMatch = responseText.match(/```(?:json)?\s*([\s\S]*?)```/);
  if (jsonMatch) {
    jsonStr = jsonMatch[1];
  }

  try {
    const parsed = JSON.parse(jsonStr.trim()) as AIPlanResponse;
    return parsed;
  } catch (e) {
    console.error('Failed to parse AI plan response:', responseText);
    throw new Error('AI returned invalid plan format');
  }
};