import { cache } from 'react';

import { AccountWithParams } from '@/packages/features/accounts/src/types/accounts';
import { createUserAnalysesApi } from '@/packages/features/user-analyses/src/server/api';
import { getSupabaseServerClient } from '@/packages/supabase/src/clients/server-client';
import { Database } from '@/packages/supabase/src/database.types';
import OpenAI from 'openai';

import PersonalCode from '~/lib/utils';

import { OrderAnalysisCard } from '../../_components/order-analyses-cards';

export const loadRecommendations = cache(recommendationsLoader);

type AnalysisResponses =
  Database['medreport']['Functions']['get_latest_analysis_response_elements_for_current_user']['Returns'];

const getLatestResponseTime = (items: AnalysisResponses) => {
  if (!items?.length) return null;

  let latest = null;
  for (const it of items) {
    const d = new Date(it.response_time);
    const t = d.getTime();
    if (!Number.isNaN(t) && (latest === null || t > latest.getTime())) {
      latest = d;
    }
  }
  return latest;
};

async function recommendationsLoader(
  analyses: OrderAnalysisCard[],
  account: AccountWithParams | null,
): Promise<string[]> {
  if (!process.env.OPENAI_API_KEY) {
    return [];
  }
  if (!account?.personal_code) {
    return [];
  }
  const supabaseClient = getSupabaseServerClient();
  const userAnalysesApi = createUserAnalysesApi(supabaseClient);
  const analysisResponses = await userAnalysesApi.getAllUserAnalysisResponses();
  const analysesRecommendationsPromptId =
    process.env.PROMPT_ID_ANALYSIS_RECOMMENDATIONS;
  const latestResponseTime = getLatestResponseTime(analysisResponses);
  const latestISO = latestResponseTime
    ? new Date(latestResponseTime).toISOString()
    : new Date('2025').toISOString();

  if (!analysesRecommendationsPromptId) {
    console.error('No prompt ID for analysis recommendations');
    return [];
  }

  const previouslyRecommended = await supabaseClient
    .schema('medreport')
    .from('ai_responses')
    .select('*')
    .eq('account_id', account.id)
    .eq('prompt_id', analysesRecommendationsPromptId)
    .eq('latest_data_change', latestISO);

  if (previouslyRecommended.data?.[0]?.response) {
    return JSON.parse(previouslyRecommended.data[0].response as string)
      .recommended;
  }

  const openAIClient = new OpenAI();
  const { gender, age } = PersonalCode.parsePersonalCode(account.personal_code);
  const weight = account.accountParams?.weight || 'unknown';

  const formattedAnalysisResponses = analysisResponses.map(
    ({
      analysis_name_lab,
      response_value,
      norm_upper,
      norm_lower,
      norm_status,
    }) => ({
      name: analysis_name_lab,
      value: response_value,
      normUpper: norm_upper,
      normLower: norm_lower,
      normStatus: norm_status,
    }),
  );
  const formattedAnalyses = analyses.map(({ description, title }) => ({
    description,
    title,
  }));

  let response;

  try {
    response = await openAIClient.responses.create({
      store: false,
      prompt: {
        id: analysesRecommendationsPromptId,
        variables: {
          analyses: JSON.stringify(formattedAnalyses),
          results: JSON.stringify(formattedAnalysisResponses),
          gender: gender.value,
          age: age.toString(),
          weight: weight.toString(),
        },
      },
    });
  } catch (error) {
    console.error('Error calling OpenAI: ', error);
    return [];
  }

  const json = JSON.parse(response.output_text);

  try {
    await supabaseClient
      .schema('medreport')
      .from('ai_responses')
      .insert({
        account_id: account.id,
        prompt_name: 'Analysis Recommendations',
        prompt_id: analysesRecommendationsPromptId,
        input: JSON.stringify({
          analyses: formattedAnalyses,
          results: formattedAnalysisResponses,
          gender,
          age,
          weight,
        }),
        latest_data_change: latestISO,
        response: response.output_text,
      });
  } catch (error) {
    console.error('Error saving AI response: ', error);
  }

  return json.recommended;
}
