import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import {
  STOCK_ALERT_TYPE_OPTIONS,
  createStockAlert,
  deleteStockAlert,
  listStockAlerts,
  sendCurrentPriceStockAlertWebPush,
  searchStockAlertCandidates,
  saveStockAlerts,
  updateStockAlert,
  updateStockAlertLayoutFeatureDescription,
} from '../services/stock-alert-service.js';

const filterTypeSchema = z.enum(STOCK_ALERT_TYPE_OPTIONS.map((option) => option.value) as [string, ...string[]]).default('all');

const stockAlertMutationSchema = z
  .object({
    id: z.string().trim().optional(),
    stockCode: z.string().trim().optional(),
    stockName: z.string().trim().optional(),
    alertType: z.string().trim().optional(),
    alertTypes: z.array(z.string().trim()).optional(),
  })
  .transform((value) => ({
    id: value.id,
    stockCode: value.stockCode,
    stockName: value.stockName,
    alertTypes: value.alertTypes?.length
      ? value.alertTypes
      : value.alertType?.trim()
        ? [value.alertType.trim()]
        : [],
  }));

const stockAlertMutationBodySchema = z
  .object({
    stockCode: z.string().trim().optional(),
    stockName: z.string().trim().optional(),
    alertType: z.string().trim().optional(),
    alertTypes: z.array(z.string().trim()).optional(),
  })
  .transform((value) => ({
    stockCode: value.stockCode,
    stockName: value.stockName,
    alertTypes: value.alertTypes?.length
      ? value.alertTypes
      : value.alertType?.trim()
        ? [value.alertType.trim()]
        : [],
  }));

export async function registerStockAlertRoutes(app: FastifyInstance) {
  app.get('/api/stock-alerts/search', async (request) => {
    const query = z
      .object({
        query: z.string().trim().min(1),
        limit: z.coerce.number().int().min(1).max(50).optional(),
      })
      .parse(request.query ?? {});

    const items = await searchStockAlertCandidates(query.query, query.limit ?? 20);

    return {
      ok: true,
      items,
    };
  });

  app.get('/api/stock-alerts', async (request) => {
    const query = z
      .object({
        alertType: filterTypeSchema.optional(),
      })
      .parse(request.query ?? {});
    const alertType = (query.alertType ?? 'all') as 'all' | 'price' | 'top3';

    await updateStockAlertLayoutFeatureDescription().catch(() => false);
    const items = await listStockAlerts(alertType);

    return {
      ok: true,
      items,
    };
  });

  app.post('/api/stock-alerts/notify-current-price', async () => {
    const result = await sendCurrentPriceStockAlertWebPush();

    return {
      ok: result.ok,
      skipped: Boolean(result.web?.skipped),
      title: result.title,
      body: result.body,
      itemCount: result.itemCount,
      lines: result.lines,
      ios: result.ios,
      web: result.web,
    };
  });

  app.post('/api/stock-alerts', async (request) => {
    const payload = stockAlertMutationSchema.parse(request.body ?? {});
    const item = await createStockAlert(payload);
    await updateStockAlertLayoutFeatureDescription().catch(() => false);

    return {
      ok: true,
      item,
    };
  });

  app.patch('/api/stock-alerts/:id', async (request) => {
    const params = z.object({ id: z.string().trim().min(1) }).parse(request.params ?? {});
    const payload = stockAlertMutationBodySchema.parse(request.body ?? {});
    const item = await updateStockAlert(params.id, payload);
    await updateStockAlertLayoutFeatureDescription().catch(() => false);

    return {
      ok: true,
      item,
    };
  });

  app.put('/api/stock-alerts/batch', async (request) => {
    const payload = z.object({ items: z.array(stockAlertMutationSchema).default([]) }).parse(request.body ?? {});
    const items = await saveStockAlerts(payload.items);
    await updateStockAlertLayoutFeatureDescription().catch(() => false);

    return {
      ok: true,
      items,
    };
  });

  app.delete('/api/stock-alerts/:id', async (request) => {
    const params = z.object({ id: z.string().trim().min(1) }).parse(request.params ?? {});
    await deleteStockAlert(params.id);
    await updateStockAlertLayoutFeatureDescription().catch(() => false);

    return {
      ok: true,
      id: params.id,
    };
  });
}
