import type { Context } from 'telegraf';
import { z } from 'zod';
import type { Db } from '../db/sqlite.js';
import { queryMessages } from '../db/messages.js';
import { generateTextCLI } from '../gemini/cli.js';
import { sendChunked } from '../agent/chunker.js';
import { logger } from '../utils/logger.js';

export interface SummarizeOptions {
  db: Db;
  chatId: number;
  googleApiKey: string;
}

// --- Query parser ---

// The model is prompted for this shape but its output is untrusted: the query it summarizes
// is attacker-supplied chat text, so every field is re-checked at runtime before it reaches SQL.
const parsedQuerySchema = z.object({
  fromDate: z.number().int().nonnegative().nullable().catch(null),
  limit: z.number().int().positive().max(1000).nullable().catch(null),
  userFilter: z.string().max(200).nullable().catch(null),
  topicFilter: z.string().max(200).nullable().catch(null),
});

interface ParsedQuery {
  fromDate: number | null;
  limit: number | null;
  userFilter: string | null;
  topicFilter: string | null;
  rawQuery: string;
}

async function parseQuery(query: string, apiKey: string): Promise<ParsedQuery> {
  const now = Math.floor(Date.now() / 1000);

  const prompt = `Parse this Telegram chat summarize query into structured JSON.
Now (Unix timestamp): ${now}
Today starts at: ${getTodayStart()}

Query: "${query}"

Return ONLY valid JSON with these fields:
{
  "fromDate": <Unix timestamp or null>,
  "limit": <number of messages or null>,
  "userFilter": <username or first name to filter by, or null>,
  "topicFilter": <topic/subject to focus on, or null>
}

Examples:
- "1 hour" → fromDate = ${now - 3600}, limit null, userFilter null, topicFilter null
- "last 5 hours" → fromDate = ${now - 18000}, limit null, userFilter null, topicFilter null
- "today" → fromDate = ${getTodayStart()}, limit null, userFilter null, topicFilter null
- "last week" → fromDate = ${now - 604800}, limit null, userFilter null, topicFilter null
- "last 10 sentences by AP" → fromDate null, limit 10, userFilter "AP", topicFilter null
- "AP's general opinions about Astro" → fromDate null, limit null, userFilter "AP", topicFilter "Astro"
- "last 3 days by Alex about payments" → fromDate ${now - 259200}, limit null, userFilter "Alex", topicFilter "payments"`;

  const raw = await generateTextCLI(prompt, apiKey, 'summarize');

  // Extract JSON from response (Gemini may wrap it in markdown)
  const match = raw.match(/\{[\s\S]*\}/);
  if (!match) throw new Error('Failed to parse query structure');

  const parsed = parsedQuerySchema.parse(JSON.parse(match[0]));

  return { ...parsed, rawQuery: query };
}

function getTodayStart(): number {
  const now = new Date();
  return Math.floor(new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() / 1000);
}

// --- Handler factory ---

export function makeSummarizeHandler(opts: SummarizeOptions) {
  return async function summarizeHandler(ctx: Context): Promise<void> {
    const msgText = ctx.message && 'text' in ctx.message ? ctx.message.text : '';
    const query = msgText.replace(/^\/summarize\s*/i, '').trim();

    if (!query) {
      await ctx.reply(
        'Usage: /summarize <query>\n\nExamples:\n' +
          '  /summarize last 1 hour\n' +
          '  /summarize today\n' +
          '  /summarize last week',
      );
      return;
    }

    await ctx.reply('🔍 Analyzing conversation...');

    let parsed: ParsedQuery;
    try {
      parsed = await parseQuery(query, opts.googleApiKey);
      logger.debug('summarize query parsed', { parsed });
    } catch {
      await ctx.reply('Could not understand that query. Try: /summarize last 2 hours');
      return;
    }

    const messages = queryMessages(opts.db, {
      chatId: opts.chatId,
      fromDate: parsed.fromDate ?? undefined,
      limit: parsed.limit ?? undefined,
      userFilter: parsed.userFilter ?? undefined,
    });

    if (messages.length === 0) {
      await ctx.reply('No messages found matching that query.');
      return;
    }

    // Format messages for the LLM
    const transcript = messages
      .map((m) => {
        const sender = m.username ? `@${m.username}` : (m.first_name ?? 'Unknown');
        const time = new Date(m.date * 1000).toLocaleString('he-IL', {
          timeZone: 'Asia/Jerusalem',
        });
        return `[${time}] ${sender}: ${m.text}`;
      })
      .join('\n');

    const topicInstruction = parsed.topicFilter
      ? `Focus specifically on messages about: "${parsed.topicFilter}". Ignore unrelated messages.`
      : 'Summarize the overall conversation.';

    const userInstruction = parsed.userFilter
      ? `Focus on messages from user "${parsed.userFilter}".`
      : '';

    const summaryPrompt = `You are summarizing a Telegram group conversation for the Hetzi project team (an Israeli deals marketplace).

${topicInstruction} ${userInstruction}

Original query: "${parsed.rawQuery}"
Messages (${messages.length} total):

${transcript}

Provide a clear, concise summary in the same language the messages are written in. If messages are in Hebrew, summarize in Hebrew. If in English, summarize in English. If mixed, use English.`;

    try {
      const summary = await generateTextCLI(summaryPrompt, opts.googleApiKey, 'summarize');
      await sendChunked(ctx, summary);
    } catch (err) {
      logger.error('summarize generation failed', {
        error: err instanceof Error ? err.message : String(err),
      });
      await ctx.reply('Failed to generate summary. Please try again.');
    }
  };
}
