import { Router } from "express";
import { z } from "zod";

import { asyncHandler } from "../../lib/async-handler.js";
import { query, queryOne } from "../../lib/db.js";
import { HttpError } from "../../lib/http-error.js";
import { requireAuth } from "../../middleware/auth.js";
import { validate } from "../../middleware/validate.js";
import { assertVehicleAccess } from "../permissions/access.js";

const acknowledgeAlertSchema = z.object({
  body: z.object({}).default({}),
  query: z.object({}).default({}),
  params: z.object({
    id: z.string().uuid(),
  }),
});

export const alertsRouter = Router();

alertsRouter.use(requireAuth);

alertsRouter.get(
  "/active",
  asyncHandler(async (request, response) => {
    if (!request.user) {
      throw new HttpError(401, "Missing authenticated user");
    }

    const rows = request.user.role === "admin"
      ? await query<{
          id: string;
          vehicle_id: string;
          vehicle_name: string;
          vehicle_type: "passenger" | "delivery";
          imei: string | null;
          speed: number;
          triggered_at: string;
          acknowledged_at: string | null;
        }>(
          `
            select
              va.id,
              va.vehicle_id,
              v.name as vehicle_name,
              v.vehicle_type,
              va.imei,
              va.speed,
              va.triggered_at,
              va.acknowledged_at
            from vehicle_alerts va
            inner join vehicles v on v.id = va.vehicle_id
            where va.acknowledged_at is null
            order by va.triggered_at desc
          `,
        )
      : await query<{
          id: string;
          vehicle_id: string;
          vehicle_name: string;
          vehicle_type: "passenger" | "delivery";
          imei: string | null;
          speed: number;
          triggered_at: string;
          acknowledged_at: string | null;
        }>(
          `
            select
              va.id,
              va.vehicle_id,
              v.name as vehicle_name,
              v.vehicle_type,
              va.imei,
              va.speed,
              va.triggered_at,
              va.acknowledged_at
            from vehicle_alerts va
            inner join vehicles v on v.id = va.vehicle_id
            inner join user_vehicle_permissions uvp on uvp.vehicle_id = va.vehicle_id
            where va.acknowledged_at is null
              and uvp.user_id = $1
            order by va.triggered_at desc
          `,
          [request.user.id],
        );

    response.json({
      items: rows.map((row) => ({
        id: row.id,
        vehicleId: row.vehicle_id,
        vehicleName: row.vehicle_name,
        vehicleKind: row.vehicle_type,
        imei: row.imei,
        speed: row.speed,
        triggeredAt: row.triggered_at,
        acknowledgedAt: row.acknowledged_at,
      })),
    });
  }),
);

alertsRouter.get(
  "/recent",
  asyncHandler(async (request, response) => {
    if (!request.user) {
      throw new HttpError(401, "Missing authenticated user");
    }

    const rows = request.user.role === "admin"
      ? await query<{
          id: string;
          vehicle_id: string;
          vehicle_name: string;
          vehicle_type: "passenger" | "delivery";
          imei: string | null;
          speed: number;
          triggered_at: string;
          acknowledged_at: string | null;
        }>(
          `
            select
              va.id,
              va.vehicle_id,
              v.name as vehicle_name,
              v.vehicle_type,
              va.imei,
              va.speed,
              va.triggered_at,
              va.acknowledged_at
            from vehicle_alerts va
            inner join vehicles v on v.id = va.vehicle_id
            where va.triggered_at >= now() - interval '7 days'
            order by va.triggered_at desc
          `,
        )
      : await query<{
          id: string;
          vehicle_id: string;
          vehicle_name: string;
          vehicle_type: "passenger" | "delivery";
          imei: string | null;
          speed: number;
          triggered_at: string;
          acknowledged_at: string | null;
        }>(
          `
            select
              va.id,
              va.vehicle_id,
              v.name as vehicle_name,
              v.vehicle_type,
              va.imei,
              va.speed,
              va.triggered_at,
              va.acknowledged_at
            from vehicle_alerts va
            inner join vehicles v on v.id = va.vehicle_id
            inner join user_vehicle_permissions uvp on uvp.vehicle_id = va.vehicle_id
            where va.triggered_at >= now() - interval '7 days'
              and uvp.user_id = $1
            order by va.triggered_at desc
          `,
          [request.user.id],
        );

    response.json({
      items: rows.map((row) => ({
        id: row.id,
        vehicleId: row.vehicle_id,
        vehicleName: row.vehicle_name,
        vehicleKind: row.vehicle_type,
        imei: row.imei,
        speed: row.speed,
        triggeredAt: row.triggered_at,
        acknowledgedAt: row.acknowledged_at,
      })),
    });
  }),
);

alertsRouter.patch(
  "/:id/acknowledge",
  validate(acknowledgeAlertSchema),
  asyncHandler(async (request, response) => {
    if (!request.user) {
      throw new HttpError(401, "Missing authenticated user");
    }

    const alert = await queryOne<{ id: string; vehicle_id: string; acknowledged_at: string | null }>(
      `
        select id, vehicle_id, acknowledged_at
        from vehicle_alerts
        where id = $1
      `,
      [request.params.id],
    );

    if (!alert) {
      throw new HttpError(404, "Alert not found");
    }

    await assertVehicleAccess(request.user, alert.vehicle_id);

    const acknowledged = await queryOne<{ id: string; acknowledged_at: string }>(
      `
        update vehicle_alerts
        set
          acknowledged_at = coalesce(acknowledged_at, now()),
          acknowledged_by = coalesce(acknowledged_by, $2)
        where id = $1
        returning id, acknowledged_at
      `,
      [request.params.id, request.user.id],
    );

    response.json({
      item: {
        id: acknowledged?.id ?? request.params.id,
        acknowledgedAt: acknowledged?.acknowledged_at ?? alert.acknowledged_at ?? new Date().toISOString(),
      },
    });
  }),
);
