import { sha256Hex } from '$lib/server/crypto';
import { icsHorizonMonths } from '$lib/server/env';
import { buildIcsCalendar, checkIcsRateLimit } from '$lib/server/ics';
import { toIsoSqlUTC, ymdUTC, addMonthsUTC } from '$lib/server/datetime';

type TaskRow = { id: number; description: string; due_date: string; group_name: string | null };

/**
 * Validate the ICS token, returning the DB row or an error Response.
 */
export async function validateIcsToken(
  db: any,
  token: string,
  expectedType: string
): Promise<{ row: any } | Response> {
  if (!token) return new Response('Not Found', { status: 404 });

  const tokenHash = await sha256Hex(token);
  const row = db
    .prepare(
      `SELECT id, type, user_id, group_id, revoked_at
       FROM calendar_tokens
       WHERE token_hash = ?
       LIMIT 1`
    )
    .get(tokenHash) as any;

  if (!row) return new Response('Not Found', { status: 404 });
  if (row.revoked_at) return new Response('Gone', { status: 410 });
  if (String(row.type) !== expectedType) return new Response('Not Found', { status: 404 });

  return { row };
}

/**
 * Build the ICS feed response: rate limit, query tasks, map events, build calendar,
 * handle ETag / 304, update last_used_at, return 200 with ETag.
 */
export async function buildIcsFeed(
  db: any,
  tokenHash: string,
  row: any,
  request: Request,
  title: string,
  tasks: TaskRow[]
): Promise<Response> {
  // Rate limit
  const rl = checkIcsRateLimit(tokenHash);
  if (!rl.ok) {
    return new Response('Too Many Requests', {
      status: 429,
      headers: { 'Retry-After': String(rl.retryAfterSec || 60) }
    });
  }

  // Map to events
  const events = tasks.map((t) => ({
    id: t.id,
    description: t.description,
    due_date: t.due_date,
    group_name: t.group_name || null,
    prefix: 'T' as const
  }));

  const { body, etag } = await buildIcsCalendar(title, events);

  // 304 if ETag matches
  const inm = request.headers.get('if-none-match');
  if (inm && inm === etag) {
    return new Response(null, { status: 304, headers: { ETag: etag, 'Cache-Control': 'public, max-age=300' } });
  }

  db.prepare(`UPDATE calendar_tokens SET last_used_at = ? WHERE id = ?`).run(toIsoSqlUTC(), row.id);

  return new Response(body, {
    status: 200,
    headers: {
      'content-type': 'text/calendar; charset=utf-8',
      'cache-control': 'public, max-age=300',
      ETag: etag
    }
  });
}

/** Compute the YMD date range for ICS queries. */
export function icsDateRange(): { startYmd: string; endYmd: string } {
  const today = new Date();
  return {
    startYmd: ymdUTC(today),
    endYmd: ymdUTC(addMonthsUTC(today, icsHorizonMonths))
  };
}
