import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import {
  listWebPushSubscriptions,
  getAutomationNotificationPreference,
  getWebPushConfig,
  registerAutomationNotificationPreferenceSchema,
  registerWebPushSubscription,
  registerWebPushSubscriptionSchema,
  sendNotifications,
  sendIosNotificationSchema,
  setupNotificationTables,
  upsertAutomationNotificationPreference,
  unregisterWebPushSubscription,
  unregisterWebPushSubscriptionSchema,
} from '../services/notification-service.js';
import {
  createNotificationMessage,
  deleteNotificationMessage,
  getNotificationMessage,
  listNotificationMessages,
  notificationMessageListQuerySchema,
  notificationMessagePayloadSchema,
  notificationMessageReadPayloadSchema,
  updateNotificationMessageReadState,
} from '../services/notification-message-service.js';

const automationNotificationPreferenceQuerySchema = z.object({
  targetKind: z.enum(['client', 'web-endpoint']).optional(),
  targetId: z.string().trim().min(1).max(1000).optional(),
});

function getClientIdHeader(request: { headers: Record<string, string | string[] | undefined> }) {
  const rawClientId = request.headers['x-client-id'];
  const clientId = Array.isArray(rawClientId) ? rawClientId[0] : rawClientId;
  return clientId?.trim() ?? '';
}

export async function registerNotificationRoutes(app: FastifyInstance) {
  app.post('/api/notifications/setup', async () => setupNotificationTables());

  app.get('/api/notifications/subscriptions/web', async () => ({
    items: await listWebPushSubscriptions(),
  }));

  app.get('/api/notifications/webpush/config', async () => getWebPushConfig());

  app.get('/api/notifications/messages', async (request) => {
    const query = notificationMessageListQuerySchema.parse(request.query ?? {});
    const clientId = getClientIdHeader(request);
    return {
      ok: true,
      ...(await listNotificationMessages(query, clientId)),
    };
  });

  app.get('/api/notifications/messages/:id', async (request, reply) => {
    const id = z.coerce.number().int().positive().parse((request.params as { id: string }).id);
    const item = await getNotificationMessage(id);

    if (!item) {
      return reply.code(404).send({
        message: '알림 메시지를 찾을 수 없습니다.',
      });
    }

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

  app.post('/api/notifications/messages', async (request) => {
    const item = await createNotificationMessage(notificationMessagePayloadSchema.parse(request.body ?? {}));

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

  app.patch('/api/notifications/messages/:id', async (request, reply) => {
    const id = z.coerce.number().int().positive().parse((request.params as { id: string }).id);
    const item = await updateNotificationMessageReadState(id, notificationMessageReadPayloadSchema.parse(request.body ?? {}));

    if (!item) {
      return reply.code(404).send({
        message: '상태를 변경할 알림 메시지를 찾을 수 없습니다.',
      });
    }

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

  app.delete('/api/notifications/messages/:id', async (request, reply) => {
    const id = z.coerce.number().int().positive().parse((request.params as { id: string }).id);
    const deleted = await deleteNotificationMessage(id);

    if (!deleted) {
      return reply.code(404).send({
        message: '삭제할 알림 메시지를 찾을 수 없습니다.',
      });
    }

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

  app.get('/api/notifications/preferences/automation', async (request) => {
    const query = automationNotificationPreferenceQuerySchema.parse(request.query ?? {});
    const targetId = query.targetId || getClientIdHeader(request);
    const targetKind = query.targetId ? query.targetKind ?? 'client' : 'client';

    return {
      ok: true,
      automation: await getAutomationNotificationPreference(targetId, targetKind),
    };
  });

  app.put('/api/notifications/preferences/automation', async (request, reply) => {
    try {
      const payload = registerAutomationNotificationPreferenceSchema.parse(request.body ?? {});
      const targetId = payload.targetId || getClientIdHeader(request);

      if (!targetId) {
        throw new Error('알림 설정을 저장할 클라이언트 ID가 없습니다.');
      }

      return upsertAutomationNotificationPreference({
        ...payload,
        targetId,
      });
    } catch (error) {
      return reply.code(409).send({
        message: error instanceof Error ? error.message : '알림 설정 저장에 실패했습니다.',
      });
    }
  });

  app.put('/api/notifications/subscriptions/web', async (request) => {
    const payload = registerWebPushSubscriptionSchema.parse(request.body ?? {});
    return registerWebPushSubscription(payload);
  });

  app.delete('/api/notifications/subscriptions/web', async (request) => {
    const payload = unregisterWebPushSubscriptionSchema.parse(request.body ?? {});
    return unregisterWebPushSubscription(payload.endpoint);
  });

  app.post('/api/notifications/send', async (request) => {
    const payload = sendIosNotificationSchema.parse(request.body ?? {});
    return sendNotifications(payload);
  });

  app.post('/api/notifications/send-test', async (request) => {
    const payload = sendIosNotificationSchema.parse(request.body ?? {});
    return sendNotifications(payload);
  });
}
