import type { IncomingMessage, ServerResponse } from "node:http";
import {
  getCalendars,
  getCalendar,
  getEvents,
  getEvent,
  createEvent,
  updateEvent,
  deleteEvent,
  createReminder,
  deleteReminder,
  getGoogleCachedEvents,
} from "./db.js";
import type { CreateEventRequest, UpdateEventRequest } from "./types.js";
import { listSharedCalendars, loadSyncConfig, saveSyncConfig } from "./google-calendar.js";

const ORBIT_URL = process.env.ORBIT_URL || "";

async function logOrbitInteraction(personName: string, eventTitle: string, eventId: string, eventStart: string): Promise<void> {
  if (!ORBIT_URL) return;
  try {
    await fetch(`${ORBIT_URL}/interactions`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        contact_name: personName,
        type: "calendar",
        occurred_at: new Date(eventStart).getTime() || Date.now(),
        summary: `Calendar event: ${eventTitle}`,
        metadata: { event_id: eventId, event_title: eventTitle },
      }),
      signal: AbortSignal.timeout(5000),
    });
  } catch {
    // Orbit may be offline — graceful degradation
  }
}

function json(res: ServerResponse, data: unknown, status = 200): void {
  res.writeHead(status, { "Content-Type": "application/json" });
  res.end(JSON.stringify(data));
}

function error(res: ServerResponse, message: string, status = 400): void {
  json(res, { error: message }, status);
}

async function readBody(req: IncomingMessage): Promise<string> {
  const chunks: Buffer[] = [];
  let size = 0;
  for await (const chunk of req) {
    size += (chunk as Buffer).length;
    if (size > 1_048_576) throw new Error("Body too large");
    chunks.push(chunk as Buffer);
  }
  return Buffer.concat(chunks).toString("utf8");
}

export function handleGetCalendars(_req: IncomingMessage, res: ServerResponse): void {
  json(res, getCalendars());
}

export function handleGetCalendar(_req: IncomingMessage, res: ServerResponse, id: string): void {
  const cal = getCalendar(id);
  if (!cal) return error(res, "Calendar not found", 404);
  json(res, cal);
}

export function handleGetEvents(req: IncomingMessage, res: ServerResponse): void {
  const url = new URL(req.url!, `http://localhost`);
  const params = {
    calendar_id: url.searchParams.get("calendar_id") ?? undefined,
    start: url.searchParams.get("start") ?? undefined,
    end: url.searchParams.get("end") ?? undefined,
    person: url.searchParams.get("person") ?? undefined,
  };
  json(res, getEvents(params));
}

export async function handleCreateEvent(req: IncomingMessage, res: ServerResponse): Promise<void> {
  try {
    const body = JSON.parse(await readBody(req)) as CreateEventRequest;
    if (!body.calendar_id || !body.title || !body.start_time || !body.end_time || !body.created_by) {
      return error(res, "Missing required fields: calendar_id, title, start_time, end_time, created_by");
    }
    const event = createEvent(body);
    json(res, event, 201);

    if (body.people && body.people.length > 0) {
      for (const person of body.people) {
        logOrbitInteraction(person.person_name, body.title, event.id, body.start_time).catch(() => {});
      }
    }
  } catch (e) {
    error(res, (e as Error).message, 500);
  }
}

export function handleGetEvent(_req: IncomingMessage, res: ServerResponse, id: string): void {
  const event = getEvent(id);
  if (!event) return error(res, "Event not found", 404);
  json(res, event);
}

export async function handleUpdateEvent(req: IncomingMessage, res: ServerResponse, id: string): Promise<void> {
  try {
    const body = JSON.parse(await readBody(req)) as UpdateEventRequest;
    const event = updateEvent(id, body);
    if (!event) return error(res, "Event not found", 404);
    json(res, event);
  } catch (e) {
    error(res, (e as Error).message, 500);
  }
}

export function handleDeleteEvent(_req: IncomingMessage, res: ServerResponse, id: string): void {
  const deleted = deleteEvent(id);
  if (!deleted) return error(res, "Event not found", 404);
  json(res, { ok: true });
}

export async function handleUpdateEventPeople(req: IncomingMessage, res: ServerResponse, eventId: string): Promise<void> {
  try {
    const body = JSON.parse(await readBody(req)) as {
      people: { person_name: string; invite_preference: string }[];
    };
    const event = updateEvent(eventId, { people: body.people as UpdateEventRequest["people"] });
    if (!event) return error(res, "Event not found", 404);
    json(res, event);

    if (body.people && body.people.length > 0) {
      for (const person of body.people) {
        logOrbitInteraction(person.person_name, event.title, eventId, event.start_time).catch(() => {});
      }
    }
  } catch (e) {
    error(res, (e as Error).message, 500);
  }
}

export async function handleCreateReminder(req: IncomingMessage, res: ServerResponse): Promise<void> {
  try {
    const body = JSON.parse(await readBody(req)) as {
      event_id: string;
      person_name: string;
      remind_at: string;
    };
    if (!body.event_id || !body.person_name || !body.remind_at) {
      return error(res, "Missing required fields: event_id, person_name, remind_at");
    }
    const reminder = createReminder(body.event_id, body.person_name, body.remind_at);
    json(res, reminder, 201);
  } catch (e) {
    error(res, (e as Error).message, 500);
  }
}

export function handleDeleteReminder(_req: IncomingMessage, res: ServerResponse, id: string): void {
  const deleted = deleteReminder(id);
  if (!deleted) return error(res, "Reminder not found", 404);
  json(res, { ok: true });
}

export function handleGetGoogleCachedEvents(req: IncomingMessage, res: ServerResponse): void {
  const url = new URL(req.url!, `http://localhost`);
  const params = {
    start: url.searchParams.get("start") ?? undefined,
    end: url.searchParams.get("end") ?? undefined,
    person_email: url.searchParams.get("person_email") ?? undefined,
  };
  json(res, getGoogleCachedEvents(params));
}

const startedAt = Date.now();

export function handleHealth(_req: IncomingMessage, res: ServerResponse): void {
  json(res, {
    status: "online",
    uptime: Math.floor((Date.now() - startedAt) / 1000),
    version: "1.0.0",
  });
}

export async function handleGetSharedCalendars(_req: IncomingMessage, res: ServerResponse): Promise<void> {
  const calendars = await listSharedCalendars();
  json(res, calendars);
}

export function handleGetSyncConfig(_req: IncomingMessage, res: ServerResponse): void {
  json(res, loadSyncConfig());
}

export async function handlePutSyncConfig(req: IncomingMessage, res: ServerResponse): Promise<void> {
  try {
    const body = JSON.parse(await readBody(req));
    saveSyncConfig(body);
    json(res, { ok: true });
  } catch (e) {
    error(res, (e as Error).message, 500);
  }
}
