import type { FastifyInstance, FastifyRequest } from 'fastify';
import { BadRequestError, NotFoundError } from '@bytelyst/errors';
import { PRODUCT_ID } from '../../lib/product-config.js';
import { getUserId } from '../../lib/request-context.js';
import { getIpcBridge } from '../../lib/ipc-bridge.js';
import {
  CreateScheduleSchema,
  PauseScheduleSchema,
  ScheduleIdParamsSchema,
  UpdateScheduleSchema,
} from './types.js';

function buildAuth(req: FastifyRequest): Record<string, unknown> {
  const userId = getUserId(req);
  const role = (req.jwtPayload as Record<string, unknown> | undefined)?.role ?? 'user';
  return { userId, role, productId: PRODUCT_ID, isPlatformAuth: !!req.jwtPayload };
}

function throwScheduleError(error: { code?: number; message: string }): never {
  if (error.code === -32001) throw new NotFoundError('Schedule not found');
  throw new BadRequestError(error.message);
}

export async function scheduleRoutes(app: FastifyInstance) {
  const bridge = getIpcBridge();

  app.get('/api/schedule', async req => {
    if (!bridge.isRunning) {
      return { schedules: [] };
    }

    const resp = await bridge.call('list_schedules', { auth: buildAuth(req) });
    if (resp.error) throwScheduleError(resp.error);
    return resp.result;
  });

  app.post('/api/schedule', async req => {
    const parsed = CreateScheduleSchema.safeParse(req.body);
    if (!parsed.success)
      throw new BadRequestError(parsed.error.issues.map(issue => issue.message).join('; '));
    if (!bridge.isRunning) throw new BadRequestError('IPC bridge unavailable');

    const resp = await bridge.call('create_schedule', {
      auth: buildAuth(req),
      ...parsed.data,
    });
    if (resp.error) throwScheduleError(resp.error);
    return resp.result;
  });

  app.patch('/api/schedule/:id', async req => {
    const params = ScheduleIdParamsSchema.safeParse(req.params);
    if (!params.success)
      throw new BadRequestError(params.error.issues.map(issue => issue.message).join('; '));

    const body = UpdateScheduleSchema.safeParse(req.body);
    if (!body.success)
      throw new BadRequestError(body.error.issues.map(issue => issue.message).join('; '));
    if (!bridge.isRunning) throw new NotFoundError('Schedule not found');

    const resp = await bridge.call('update_schedule', {
      auth: buildAuth(req),
      scheduleId: params.data.id,
      ...body.data,
    });
    if (resp.error) throwScheduleError(resp.error);
    return resp.result;
  });

  app.delete('/api/schedule/:id', async req => {
    const parsed = ScheduleIdParamsSchema.safeParse(req.params);
    if (!parsed.success)
      throw new BadRequestError(parsed.error.issues.map(issue => issue.message).join('; '));
    if (!bridge.isRunning) throw new NotFoundError('Schedule not found');

    const resp = await bridge.call('delete_schedule', {
      auth: buildAuth(req),
      scheduleId: parsed.data.id,
    });
    if (resp.error) throwScheduleError(resp.error);
    return resp.result;
  });

  app.post('/api/schedule/:id/pause', async req => {
    const params = ScheduleIdParamsSchema.safeParse(req.params);
    if (!params.success)
      throw new BadRequestError(params.error.issues.map(issue => issue.message).join('; '));

    const body = PauseScheduleSchema.safeParse(req.body ?? {});
    if (!body.success)
      throw new BadRequestError(body.error.issues.map(issue => issue.message).join('; '));
    if (!bridge.isRunning) throw new NotFoundError('Schedule not found');

    const resp = await bridge.call('pause_schedule', {
      auth: buildAuth(req),
      scheduleId: params.data.id,
      paused: body.data.paused ?? true,
    });
    if (resp.error) throwScheduleError(resp.error);
    return resp.result;
  });
}
