import { useCallback, useEffect, useMemo, useState } from 'react';
import { supabase } from '../lib/supabaseClient';
import { saveTrainingPlanWithSessions } from '../lib/trainingPlanService';
import { generateTrainingPlan } from '../utils/trainingPlanGenerator';

const mapPlanRow = (row) => ({
  id: row.id,
  patType: row.pat_type,
  status: row.status,
  analysisSnapshot: row.analysis_snapshot || {},
  durationWeeks: row.duration_weeks,
  sessionsPerWeek: row.sessions_per_week,
  generatedAt: row.generated_at,
  archivedAt: row.archived_at,
  createdAt: row.created_at,
  updatedAt: row.updated_at,
  sessions: []
});

const mapSessionRow = (row) => ({
  id: row.id,
  planId: row.plan_id,
  weekNo: row.week_no,
  sessionNo: row.session_no,
  mainExercise: row.main_exercise,
  secondaryExercises: row.secondary_exercises || [],
  tasks: row.tasks || [],
  state: row.state || 'open',
  notes: row.notes || '',
  completedAt: row.completed_at,
  createdAt: row.created_at,
  updatedAt: row.updated_at
});

const updateSessionInPlan = (plan, sessionId, patch) => {
  if (!plan) return plan;

  const hasSession = plan.sessions.some((session) => session.id === sessionId);
  if (!hasSession) return plan;

  return {
    ...plan,
    sessions: plan.sessions.map((session) =>
      session.id === sessionId
        ? {
            ...session,
            ...patch
          }
        : session
    )
  };
};

export const useTrainingPlans = ({ user, patType }) => {
  const [activePlan, setActivePlan] = useState(null);
  const [historyPlans, setHistoryPlans] = useState([]);
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState('');

  const canUseSupabase = useMemo(() => Boolean(supabase && user?.id), [user]);

  const loadPlans = useCallback(async () => {
    if (!canUseSupabase || !patType) {
      setActivePlan(null);
      setHistoryPlans([]);
      return;
    }

    setLoading(true);
    setError('');

    try {
      const { data: plansData, error: plansError } = await supabase
        .from('training_plans')
        .select('*')
        .eq('user_id', user.id)
        .eq('pat_type', patType)
        .order('generated_at', { ascending: false });

      if (plansError) throw plansError;

      const mappedPlans = (plansData || []).map(mapPlanRow);
      const planIds = mappedPlans.map((plan) => plan.id);

      let sessionsByPlan = new Map();

      if (planIds.length) {
        const { data: sessionsData, error: sessionsError } = await supabase
          .from('training_plan_sessions')
          .select('*')
          .in('plan_id', planIds)
          .order('week_no', { ascending: true })
          .order('session_no', { ascending: true });

        if (sessionsError) throw sessionsError;

        sessionsByPlan = (sessionsData || []).reduce((map, row) => {
          const session = mapSessionRow(row);
          const list = map.get(session.planId) || [];
          list.push(session);
          map.set(session.planId, list);
          return map;
        }, new Map());
      }

      const plansWithSessions = mappedPlans.map((plan) => ({
        ...plan,
        sessions: sessionsByPlan.get(plan.id) || []
      }));

      const active = plansWithSessions.find((plan) => plan.status === 'active') || plansWithSessions[0] || null;
      const history = plansWithSessions.filter((plan) => !active || plan.id !== active.id);

      setActivePlan(active);
      setHistoryPlans(history);
    } catch (loadError) {
      setError(loadError.message || 'Fehler beim Laden der Trainingspläne.');
    } finally {
      setLoading(false);
    }
  }, [canUseSupabase, patType, user?.id]);

  useEffect(() => {
    loadPlans();
  }, [loadPlans]);

  const saveGeneratedPlan = useCallback(
    async ({ analysis, durationWeeks = 4, sessionsPerWeek = 3, sessions = null }) => {
      if (!canUseSupabase || !patType) {
        return {
          ok: false,
          error: new Error('Supabase oder PAT-Typ nicht verfügbar.')
        };
      }

      setSaving(true);
      setError('');

      try {
        const preparedSessions = sessions
          ? sessions
          : generateTrainingPlan({
              topWeaknesses: analysis?.topWeaknesses || [],
              topStrengths: analysis?.topStrengths || [],
              durationWeeks,
              sessionsPerWeek
            }).sessions;

        const result = await saveTrainingPlanWithSessions({
          patType,
          analysisSnapshot: analysis,
          durationWeeks,
          sessionsPerWeek,
          sessions: preparedSessions
        });

        if (!result.ok) throw result.error;

        await loadPlans();

        return {
          ok: true,
          planId: result.planId
        };
      } catch (saveError) {
        setError(saveError.message || 'Fehler beim Speichern des Trainingsplans.');
        return {
          ok: false,
          error: saveError
        };
      } finally {
        setSaving(false);
      }
    },
    [canUseSupabase, loadPlans, patType]
  );

  const updateSessionState = useCallback(async (sessionId, nextState) => {
    if (!canUseSupabase) return { ok: false };

    const nextCompletedAt = nextState === 'done' ? new Date().toISOString() : null;

    const prevActive = activePlan;
    const prevHistory = historyPlans;

    setActivePlan((current) => updateSessionInPlan(current, sessionId, {
      state: nextState,
      completedAt: nextCompletedAt
    }));

    setHistoryPlans((current) =>
      current.map((plan) =>
        updateSessionInPlan(plan, sessionId, {
          state: nextState,
          completedAt: nextCompletedAt
        })
      )
    );

    const { error: updateError } = await supabase
      .from('training_plan_sessions')
      .update({
        state: nextState,
        completed_at: nextCompletedAt
      })
      .eq('id', sessionId);

    if (updateError) {
      setActivePlan(prevActive);
      setHistoryPlans(prevHistory);
      setError(updateError.message || 'Session-Status konnte nicht gespeichert werden.');
      return { ok: false, error: updateError };
    }

    return { ok: true };
  }, [activePlan, canUseSupabase, historyPlans]);

  const updateSessionPartial = useCallback(async (sessionId, patch) => {
    if (!canUseSupabase) return { ok: false };

    const normalizedPatch = {
      ...patch
    };

    const prevActive = activePlan;
    const prevHistory = historyPlans;

    setActivePlan((current) => updateSessionInPlan(current, sessionId, normalizedPatch));
    setHistoryPlans((current) => current.map((plan) => updateSessionInPlan(plan, sessionId, normalizedPatch)));

    const dbPatch = {};

    if (Object.prototype.hasOwnProperty.call(normalizedPatch, 'mainExercise')) {
      dbPatch.main_exercise = normalizedPatch.mainExercise;
    }
    if (Object.prototype.hasOwnProperty.call(normalizedPatch, 'secondaryExercises')) {
      dbPatch.secondary_exercises = normalizedPatch.secondaryExercises;
    }
    if (Object.prototype.hasOwnProperty.call(normalizedPatch, 'tasks')) {
      dbPatch.tasks = normalizedPatch.tasks;
    }
    if (Object.prototype.hasOwnProperty.call(normalizedPatch, 'notes')) {
      dbPatch.notes = normalizedPatch.notes;
    }

    const { error: updateError } = await supabase
      .from('training_plan_sessions')
      .update(dbPatch)
      .eq('id', sessionId);

    if (updateError) {
      setActivePlan(prevActive);
      setHistoryPlans(prevHistory);
      setError(updateError.message || 'Session-Änderung konnte nicht gespeichert werden.');
      return { ok: false, error: updateError };
    }

    return { ok: true };
  }, [activePlan, canUseSupabase, historyPlans]);

  return {
    activePlan,
    historyPlans,
    loading,
    saving,
    error,
    loadPlans,
    saveGeneratedPlan,
    updateSessionState,
    updateSessionPartial
  };
};

export default useTrainingPlans;
