import { sql } from "@/db";

export interface ToolContext {
  childId: string;
  familyId: string;
  childName: string;
  birthDate: string;
}

// ─── Tool definitions (OpenAI function-calling schema) ──────────────────────

export const TOOL_DEFINITIONS = [
  {
    type: "function",
    function: {
      name: "get_sleep_summary",
      description: "Get sleep summary for the child (total sleep, longest stretch, wake count)",
      parameters: {
        type: "object",
        properties: {
          date_range: { type: "string", enum: ["today", "yesterday", "last_7_days", "last_30_days"], description: "Time window" },
        },
        required: ["date_range"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_feed_summary",
      description: "Get feeding summary (count, total amount, average interval)",
      parameters: {
        type: "object",
        properties: {
          date_range: { type: "string", enum: ["today", "yesterday", "last_7_days", "last_30_days"] },
        },
        required: ["date_range"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_diaper_summary",
      description: "Get diaper count by type",
      parameters: {
        type: "object",
        properties: {
          date_range: { type: "string", enum: ["today", "yesterday", "last_7_days", "last_30_days"] },
        },
        required: ["date_range"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_last_log",
      description: "Get the most recent log entry of a given type",
      parameters: {
        type: "object",
        properties: {
          type: { type: "string", enum: ["feed", "sleep", "diaper"] },
        },
        required: ["type"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_growth_trend",
      description: "Get last N growth measurements",
      parameters: {
        type: "object",
        properties: {
          metric: { type: "string", enum: ["weight", "height", "head"], description: "Which measurement" },
          n: { type: "integer", minimum: 1, maximum: 10, default: 3 },
        },
        required: ["metric"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_medication_status",
      description: "Get current medications and last dose time",
      parameters: {
        type: "object",
        properties: {
          active_only: { type: "boolean", default: true },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_vaccination_status",
      description: "Get vaccination status — completed, pending, overdue",
      parameters: { type: "object", properties: {} },
    },
  },
] as const;

// ─── Date range helper ───────────────────────────────────────────────────────

function dateRange(range: string): { start: Date; end: Date } {
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const end = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);

  switch (range) {
    case "yesterday": {
      const s = new Date(today); s.setDate(s.getDate() - 1);
      return { start: s, end: today };
    }
    case "last_7_days": {
      const s = new Date(today); s.setDate(s.getDate() - 7);
      return { start: s, end };
    }
    case "last_30_days": {
      const s = new Date(today); s.setDate(s.getDate() - 30);
      return { start: s, end };
    }
    default: // today
      return { start: today, end };
  }
}

// ─── Tool executors ──────────────────────────────────────────────────────────

async function get_sleep_summary(args: { date_range: string }, ctx: ToolContext) {
  const { start, end } = dateRange(args.date_range);
  const rows = await sql.unsafe(
    `SELECT duration_minutes, started_at, ended_at, type
     FROM sleeps WHERE child_id = $1 AND started_at >= $2 AND started_at < $3`,
    [ctx.childId, start.toISOString(), end.toISOString()]
  );
  const totalMin = rows.reduce((a: number, r: Record<string, number>) => a + (r.duration_minutes || 0), 0);
  const longest = rows.reduce((a: number, r: Record<string, number>) => Math.max(a, r.duration_minutes || 0), 0);
  return {
    range: args.date_range,
    totalHours: (totalMin / 60).toFixed(1),
    longestStretchHours: (longest / 60).toFixed(1),
    sessionsCount: rows.length,
    napCount: rows.filter((r: Record<string, string>) => r.type === "nap").length,
    nightCount: rows.filter((r: Record<string, string>) => r.type === "night_sleep").length,
  };
}

async function get_feed_summary(args: { date_range: string }, ctx: ToolContext) {
  const { start, end } = dateRange(args.date_range);
  const rows = await sql.unsafe(
    `SELECT type, amount_ml, logged_at FROM feeds WHERE child_id = $1 AND logged_at >= $2 AND logged_at < $3 ORDER BY logged_at ASC`,
    [ctx.childId, start.toISOString(), end.toISOString()]
  );
  const totalMl = rows.reduce((a: number, r: Record<string, number>) => a + (r.amount_ml || 0), 0);
  let avgIntervalMin: number | null = null;
  if (rows.length > 1) {
    const intervals = rows.slice(1).map((r: Record<string, string>, i: number) =>
      (new Date(r.logged_at).getTime() - new Date((rows[i] as Record<string, string>).logged_at).getTime()) / 60000
    );
    avgIntervalMin = Math.round(intervals.reduce((a: number, b: number) => a + b, 0) / intervals.length);
  }
  return {
    range: args.date_range,
    count: rows.length,
    totalMl,
    avgIntervalMinutes: avgIntervalMin,
    types: [...new Set(rows.map((r: Record<string, string>) => r.type))],
  };
}

async function get_diaper_summary(args: { date_range: string }, ctx: ToolContext) {
  const { start, end } = dateRange(args.date_range);
  const rows = await sql.unsafe(
    `SELECT type FROM diapers_logs WHERE child_id = $1 AND logged_at >= $2 AND logged_at < $3`,
    [ctx.childId, start.toISOString(), end.toISOString()]
  );
  const counts: Record<string, number> = {};
  for (const r of rows as Record<string, string>[]) { counts[r.type] = (counts[r.type] || 0) + 1; }
  return { range: args.date_range, total: rows.length, byType: counts };
}

async function get_last_log(args: { type: string }, ctx: ToolContext) {
  if (args.type === "feed") {
    const [r] = await sql.unsafe(`SELECT * FROM feeds WHERE child_id = $1 ORDER BY logged_at DESC LIMIT 1`, [ctx.childId]);
    return r ? { type: "feed", at: r.logged_at, details: { method: r.method, amountMl: r.amount_ml } } : null;
  }
  if (args.type === "sleep") {
    const [r] = await sql.unsafe(`SELECT * FROM sleeps WHERE child_id = $1 ORDER BY started_at DESC LIMIT 1`, [ctx.childId]);
    return r ? { type: "sleep", at: r.started_at, details: { durationMin: r.duration_minutes, sleepType: r.type } } : null;
  }
  if (args.type === "diaper") {
    const [r] = await sql.unsafe(`SELECT * FROM diapers_logs WHERE child_id = $1 ORDER BY logged_at DESC LIMIT 1`, [ctx.childId]);
    return r ? { type: "diaper", at: r.logged_at, details: { diaperType: r.type } } : null;
  }
  return null;
}

async function get_growth_trend(args: { metric: string; n?: number }, ctx: ToolContext) {
  const col = args.metric === "weight" ? "weight_kg" : args.metric === "height" ? "height_cm" : "head_circumference_cm";
  const rows = await sql.unsafe(
    `SELECT measured_at, ${col} as value FROM growth WHERE child_id = $1 AND ${col} IS NOT NULL ORDER BY measured_at DESC LIMIT $2`,
    [ctx.childId, args.n || 3]
  );
  return { metric: args.metric, readings: rows.map((r: Record<string, unknown>) => ({ at: r.measured_at, value: r.value })) };
}

async function get_medication_status(args: { active_only?: boolean }, ctx: ToolContext) {
  const meds = await sql.unsafe(
    `SELECT m.*, (SELECT administered_at FROM medication_doses WHERE medicine_id = m.id ORDER BY administered_at DESC LIMIT 1) as last_dose_at
     FROM medicines m JOIN children c ON c.id = m.child_id WHERE c.id = $1`,
    [ctx.childId]
  );
  return { medications: meds.map((m: Record<string, unknown>) => ({ name: m.name, dose: m.dose, lastDoseAt: m.last_dose_at })) };
}

async function get_vaccination_status(_args: unknown, ctx: ToolContext) {
  const vacc = await sql.unsafe(`SELECT * FROM vaccinations WHERE child_id = $1 ORDER BY scheduled_date ASC`, [ctx.childId]);
  const now = new Date();
  const given = vacc.filter((v: Record<string, unknown>) => v.status === "given");
  const overdue = vacc.filter((v: Record<string, unknown>) => v.status !== "given" && new Date(v.scheduled_date as string) < now);
  const upcoming = vacc.filter((v: Record<string, unknown>) => v.status !== "given" && new Date(v.scheduled_date as string) >= now).slice(0, 3);
  return {
    givenCount: given.length,
    overdueCount: overdue.length,
    overdueNames: overdue.slice(0, 3).map((v: Record<string, unknown>) => v.vaccine_name),
    upcoming: upcoming.map((v: Record<string, unknown>) => ({ name: v.vaccine_name, due: v.scheduled_date })),
  };
}

// ─── Dispatcher ──────────────────────────────────────────────────────────────

export async function executeTool(name: string, args: Record<string, unknown>, ctx: ToolContext): Promise<unknown> {
  switch (name) {
    case "get_sleep_summary":    return get_sleep_summary(args as { date_range: string }, ctx);
    case "get_feed_summary":     return get_feed_summary(args as { date_range: string }, ctx);
    case "get_diaper_summary":   return get_diaper_summary(args as { date_range: string }, ctx);
    case "get_last_log":         return get_last_log(args as { type: string }, ctx);
    case "get_growth_trend":     return get_growth_trend(args as { metric: string; n?: number }, ctx);
    case "get_medication_status":return get_medication_status(args as { active_only?: boolean }, ctx);
    case "get_vaccination_status":return get_vaccination_status(args, ctx);
    default:                     return { error: `Unknown tool: ${name}` };
  }
}
