import OpenAI from "openai";
import type {
  ChatCompletionMessageParam,
  ChatCompletionTool,
} from "openai/resources/chat/completions";
import type { IdeaTags, PlanItem } from "@/types";
import {
  IdeaTagsSchema,
  SuggestIdeasSchema,
  GenerateScheduleSchema,
  RefinePlanSchema,
  SuggestAlternativesSchema,
} from "@/lib/schemas/ai";

function getClient() {
  const apiKey = process.env.DEEPSEEK_API_KEY;
  if (!apiKey) throw new Error("DEEPSEEK_API_KEY is not configured");
  return new OpenAI({ baseURL: "https://api.deepseek.com", apiKey });
}

const TAG_SYSTEM_PROMPT = `你是一个周末活动分析助手。用户会输入一条周末活动想法，你需要分析并返回结构化 JSON。

返回字段：
- category: 活动品类，必须是以下之一：
  "dining"（餐饮美食）| "outdoor"（户外活动）| "entertainment"（娱乐休闲，如电影、KTV、密室）| "shopping"（购物逛街）| "sports"（运动健身）| "culture"（文化艺术，如博物馆、展览）| "relaxation"（放松休息，如SPA、咖啡、下午茶）| "experience"（体验活动，如手作、烘焙、插花、DIY）| "nature"（自然户外，如露营、徒步、赶海）
- timeSlot: 最适合的时间段，必须是以下之一：
  "morning"（上午）| "afternoon"（下午）| "evening"（晚上）| "flexible"（任意时间都可以）| "all_day"（需要一整天）
- estimatedMinutes: 预估活动时长（整数，单位分钟）
- costLevel: 费用等级，必须是以下之一：
  "free"（免费）| "budget"（人均<50元）| "moderate"（人均50-200元）| "premium"（人均>200元）
- intensity: 体力强度，必须是以下之一：
  "chill"（轻松休闲）| "moderate"（适度活动）| "active"（需要体力）
- needsBooking: 是否需要提前预约/购票（布尔值）
- searchQuery: 在地图服务上搜索的关键词（品牌名、地名或品类名）
- searchType: 搜索策略，必须是以下之一：
  "brand"（连锁品牌，有多个分店）| "place"（唯一地点，如某个公园）| "category"（模糊品类，搜附近匹配的）

只返回 JSON，不要任何额外文字。`;

const SCHEDULE_SYSTEM_PROMPT = `你是一个周末行程规划师。根据用户选定的活动和候选地点坐标，生成最优行程安排。

规划原则：
1. 选择地理位置相近的 POI，最小化总移动距离
2. 严格遵守用餐时间窗口：午餐安排在 11:30-13:00，晚餐安排在 17:30-19:30，不得超出此范围
3. 尊重活动的时间偏好（morning 的活动放 9:00-12:00，afternoon 的活动放 13:00-17:00，evening 的活动放 19:00 以后）
4. 活动之间留出合理的交通时间（15-30分钟）
5. 如果有"category"类型的活动，选择离其他已确定地点最近的候选
6. 高低强度活动交替安排，避免连续高体力活动
7. 费用平衡，避免连续安排 premium 级别活动
8. 需要预约（needsBooking）的活动，在 reason 中提醒用户提前预约

返回 JSON 格式：
{
  "items": [
    {
      "time": "10:00",
      "activity": "原始活动描述",
      "poi": "选定的具体 POI 名称",
      "address": "详细地址",
      "lat": 31.2,
      "lng": 121.5,
      "duration": 120,
      "reason": "选择这个时间和地点的简短理由",
      "transitToNext": 20,
      "transitDescription": "地铁2号线(6站) → 地铁9号线(3站)"
    }
  ],
  "summary": "一句话总结这个行程的亮点"
}

transitToNext 为从本活动结束到下一活动的预计交通时间（分钟），根据两点地理距离估算；transitDescription 为交通方式描述（如"地铁X号线"、"公交XXX路"、"步行"）；最后一项不填这两个字段。
按时间顺序排列。只返回 JSON。`;

export interface ScheduleContext {
  ideas: {
    content: string;
    category: string;
    timeSlot: string;
    estimatedMinutes: number;
    searchQuery: string;
    searchType: string;
    costLevel?: string;
    intensity?: string;
    needsBooking?: boolean;
  }[];
  candidates: Record<
    string,
    { name: string; address: string; lat: number; lng: number; rating?: number }[]
  >;
  userLocation: { lat: number; lng: number };
  availableTime: { date: string; startHour: number; endHour: number };
}

export async function tagIdea(content: string): Promise<IdeaTags | null> {
  try {
    const client = getClient();
    const response = await client.chat.completions.create({
      model: "deepseek-chat",
      messages: [
        { role: "system", content: TAG_SYSTEM_PROMPT },
        { role: "user", content },
      ],
      response_format: { type: "json_object" },
      max_tokens: 200,
      temperature: 0.3,
    });

    const text = response.choices[0]?.message?.content;
    if (!text) return null;

    const result = IdeaTagsSchema.safeParse(JSON.parse(text));
    if (!result.success) return null;

    return result.data as IdeaTags;
  } catch (e) {
    console.error("tagIdea failed:", e);
    return null;
  }
}

const SUGGEST_SYSTEM_PROMPT = `你是一个脑洞大开的周末活动灵感助手。根据用户房间里已有的活动想法，推荐 4 个风格相近但不重复的新想法。

要求：
- 贴合已有想法的整体调性（如果偏文艺就推文艺的，偏冒险就推冒险的）
- 适当加入一些意想不到的创意，激发灵感
- 每条想法 5-15 个字，口语化、有画面感
- 不要与已有想法重复或过于相似

只返回 JSON：{ "suggestions": ["想法1", "想法2", "想法3", "想法4"] }`;

export async function suggestIdeas(existingIdeas: string[]): Promise<string[]> {
  try {
    const client = getClient();
    const response = await client.chat.completions.create({
      model: "deepseek-chat",
      messages: [
        { role: "system", content: SUGGEST_SYSTEM_PROMPT },
        { role: "user", content: `已有想法：\n${existingIdeas.map((s, i) => `${i + 1}. ${s}`).join("\n")}` },
      ],
      response_format: { type: "json_object" },
      max_tokens: 200,
      temperature: 0.9,
    });

    const text = response.choices[0]?.message?.content;
    if (!text) return [];

    const result = SuggestIdeasSchema.safeParse(JSON.parse(text));
    if (!result.success) return [];

    return result.data.suggestions
      .filter((s) => s.length > 0)
      .slice(0, 4);
  } catch (e) {
    console.error("suggestIdeas failed:", e);
    return [];
  }
}

export async function generateSchedule(
  ctx: ScheduleContext,
): Promise<{ items: PlanItem[]; summary: string } | null> {
  try {
    const client = getClient();

    const userPrompt = `
可用时间：${ctx.availableTime.date}，${ctx.availableTime.startHour}:00 - ${ctx.availableTime.endHour}:00
用户出发位置：纬度 ${ctx.userLocation.lat}，经度 ${ctx.userLocation.lng}

活动列表：
${ctx.ideas.map((idea, i) => `${i + 1}. "${idea.content}"（品类：${idea.category}，偏好时间：${idea.timeSlot}，预估${idea.estimatedMinutes}分钟${idea.costLevel ? `，费用：${idea.costLevel}` : ""}${idea.intensity ? `，强度：${idea.intensity}` : ""}${idea.needsBooking ? "，需预约" : ""}）`).join("\n")}

各活动的候选地点：
${Object.entries(ctx.candidates)
  .map(
    ([query, pois]) =>
      `"${query}" 的候选：\n${pois.map((p) => `  - ${p.name} | ${p.address} | 坐标(${p.lat},${p.lng})${p.rating ? ` | 评分${p.rating}` : ""}`).join("\n")}`,
  )
  .join("\n\n")}

请为以上活动生成最优行程安排。`;

    const response = await client.chat.completions.create({
      model: "deepseek-chat",
      messages: [
        { role: "system", content: SCHEDULE_SYSTEM_PROMPT },
        { role: "user", content: userPrompt },
      ],
      response_format: { type: "json_object" },
      max_tokens: 1500,
      temperature: 0.5,
    });

    const text = response.choices[0]?.message?.content;
    if (!text) return null;

    const result = GenerateScheduleSchema.safeParse(JSON.parse(text));
    if (!result.success) return null;

    return {
      items: result.data.items.map((item) => ({
        ...item,
        ...(item.transitToNext != null && item.transitToNext > 0
          ? { transitToNext: Math.round(item.transitToNext) }
          : { transitToNext: undefined, transitDescription: undefined }),
      })) as PlanItem[],
      summary: result.data.summary,
    };
  } catch (e) {
    console.error("generateSchedule failed:", e);
    return null;
  }
}

// ---------------------------------------------------------------------------
// refinePlan: adjust an existing plan based on a natural-language instruction
// ---------------------------------------------------------------------------

const REFINE_PLAN_SYSTEM_PROMPT = `你是一个周末行程调整助手。根据用户指令修改现有行程。规则：
1. 只改用户明确要求的部分，其余原样保留
2. 时间安排合理，活动间留交通时间
3. 若需新增活动，poi/address 可留空字符串，lat/lng 填 0
4. 严格按输入的 JSON 结构输出完整 days 数组`;

export async function refinePlan(
  days: import("@/types").WeekendPlanData[],
  instruction: string,
): Promise<import("@/types").WeekendPlanData[] | null> {
  try {
    const client = getClient();
    const response = await client.chat.completions.create({
      model: "deepseek-chat",
      messages: [
        { role: "system", content: REFINE_PLAN_SYSTEM_PROMPT },
        {
          role: "user",
          content: `当前行程：\n${JSON.stringify(days)}\n\n用户指令：${instruction}`,
        },
      ],
      response_format: { type: "json_object" },
      temperature: 0.5,
      max_tokens: 2000,
    });

    const text = response.choices[0]?.message?.content;
    if (!text) return null;

    const parsed = JSON.parse(text);
    const rawResult = parsed.days ?? parsed;
    const result = RefinePlanSchema.safeParse({ days: rawResult });
    if (!result.success) return null;

    return result.data.days as unknown as import("@/types").WeekendPlanData[];
  } catch (e) {
    console.error("refinePlan failed:", e);
    return null;
  }
}

// ---------------------------------------------------------------------------
// suggestAlternativeItems: recommend 3 alternatives for a single activity
// ---------------------------------------------------------------------------

const SUGGEST_ALT_SYSTEM_PROMPT = `你是一个周末活动推荐助手。根据当前活动推荐 3 个类似但不同的替代方案，用于替换行程中的该活动。

每个替代方案需要包含：
- activity: 活动描述（5-15字，口语化）
- searchQuery: 高德地图搜索关键词
- reason: 推荐理由（一句话）

只返回 JSON：{ "alternatives": [{ "activity", "searchQuery", "reason" }] }`;

export async function suggestAlternativeItems(
  activity: string,
  time: string,
): Promise<Array<{ activity: string; searchQuery: string; reason: string }> | null> {
  try {
    const client = getClient();
    const response = await client.chat.completions.create({
      model: "deepseek-chat",
      messages: [
        { role: "system", content: SUGGEST_ALT_SYSTEM_PROMPT },
        {
          role: "user",
          content: `当前活动：${activity}${time ? `（时间：${time}）` : ""}`,
        },
      ],
      response_format: { type: "json_object" },
      temperature: 0.8,
      max_tokens: 400,
    });

    const text = response.choices[0]?.message?.content;
    if (!text) return null;

    const result = SuggestAlternativesSchema.safeParse(JSON.parse(text));
    if (!result.success) return null;

    return result.data.alternatives.slice(0, 3) as Array<{ activity: string; searchQuery: string; reason: string }>;
  } catch (e) {
    console.error("suggestAlternativeItems failed:", e);
    return null;
  }
}

// ---------------------------------------------------------------------------
// Generic tool-calling agent loop
// ---------------------------------------------------------------------------

export interface AgentTool {
  name: string;
  description: string;
  parameters: Record<string, unknown>; // JSON Schema for the tool parameters
  execute: (args: Record<string, unknown>) => Promise<string>;
  progressBefore?: (args: Record<string, unknown>) => string;
  progressAfter?: (args: Record<string, unknown>, result: string) => string;
}

export interface AgentLoopOptions {
  systemPrompt: string;
  userPrompt: string;
  tools: AgentTool[];
  onProgress?: (message: string) => void;
  maxTurns?: number;
}

export interface AgentLoopResult {
  finalArgs: Record<string, unknown>;
  turns: number;
}

export async function runAgentLoop(
  options: AgentLoopOptions,
): Promise<AgentLoopResult | null> {
  const { systemPrompt, userPrompt, tools, onProgress, maxTurns = 15 } = options;
  const client = getClient();

  const openaiTools: ChatCompletionTool[] = tools.map((t) => ({
    type: "function" as const,
    function: {
      name: t.name,
      description: t.description,
      parameters: t.parameters,
    },
  }));

  const toolMap = new Map(tools.map((t) => [t.name, t]));

  const messages: ChatCompletionMessageParam[] = [
    { role: "system", content: systemPrompt },
    { role: "user", content: userPrompt },
  ];

  for (let turn = 0; turn < maxTurns; turn++) {
    const response = await client.chat.completions.create({
      model: "deepseek-chat",
      messages,
      tools: openaiTools,
      temperature: 0.6,
      max_tokens: 4096,
    });

    const choice = response.choices[0];
    if (!choice) break;

    const assistantMessage = choice.message;

    // Push AI thinking text to the user
    if (assistantMessage.content) {
      onProgress?.(assistantMessage.content);
    }

    // No tool calls — conversation ended
    if (!assistantMessage.tool_calls || assistantMessage.tool_calls.length === 0) {
      // Add the assistant message and break if there's nothing more to do
      messages.push({ role: "assistant", content: assistantMessage.content ?? "" });
      if (choice.finish_reason === "stop") break;
      continue;
    }

    // Add the assistant message (with tool_calls) to history
    messages.push(assistantMessage as ChatCompletionMessageParam);

    // Execute each tool call
    for (const toolCall of assistantMessage.tool_calls) {
      if (toolCall.type !== "function") continue;
      const fnName = toolCall.function.name;
      const tool = toolMap.get(fnName);
      if (!tool) {
        messages.push({
          role: "tool",
          tool_call_id: toolCall.id,
          content: JSON.stringify({ error: `Unknown tool: ${fnName}` }),
        });
        continue;
      }

      let args: Record<string, unknown>;
      try {
        args = JSON.parse(toolCall.function.arguments);
      } catch (e) {
        console.error("runAgentLoop: failed to parse tool arguments:", e);
        args = {};
      }

      // Progress: before execution
      if (tool.progressBefore) {
        onProgress?.(tool.progressBefore(args));
      }

      // Execute
      const result = await tool.execute(args);

      // Progress: after execution
      if (tool.progressAfter) {
        onProgress?.(tool.progressAfter(args, result));
      }

      // If this is finalize_plan, return immediately
      if (fnName === "finalize_plan") {
        return { finalArgs: args, turns: turn + 1 };
      }

      // Feed tool result back to the conversation
      messages.push({
        role: "tool",
        tool_call_id: toolCall.id,
        content: result,
      });
    }
  }

  // Exhausted turns without finalize
  return null;
}
