import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import { prisma, SubscriptionTier } from '@shieldsai/shared-db';
import { tierConfig, SubscriptionTier as BillingTier } from '@shieldsai/shared-billing';
import {
  watchlistService,
  scanService,
  schedulerService,
  webhookService,
} from '../services/darkwatch';

export async function darkwatchRoutes(fastify: FastifyInstance) {
  const authed = async (
    request: FastifyRequest,
    reply: FastifyReply
  ): Promise<string | null> => {
    const authReq = request as FastifyRequest & { user?: { id: string } };
    const userId = authReq.user?.id;
    if (!userId) {
      reply.code(401).send({ error: 'User ID required' });
      return null;
    }

    const subscription = await prisma.subscription.findFirst({
      where: { userId, status: 'active' },
      select: { id: true, tier: true },
    });

    if (!subscription) {
      reply.code(404).send({ error: 'Active subscription not found' });
      return null;
    }

    return subscription.id;
  };

  // GET /darkwatch/watchlist - List watchlist items
  fastify.get('/watchlist', async (request: FastifyRequest, reply: FastifyReply) => {
    const subscriptionId = await authed(request, reply);
    if (!subscriptionId) return;

    try {
      const items = await watchlistService.getItems(subscriptionId);
      return reply.send({ items });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to list watchlist';
      return reply.code(500).send({ error: message });
    }
  });

  // POST /darkwatch/watchlist - Add watchlist item
  fastify.post('/watchlist', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as FastifyRequest & { user?: { id: string } };
    const userId = authReq.user?.id;
    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    const subscription = await prisma.subscription.findFirst({
      where: { userId, status: 'active' },
      select: { id: true, tier: true },
    });

    if (!subscription) {
      return reply.code(404).send({ error: 'Active subscription not found' });
    }

    const body = request.body as { type: string; value: string };

    if (!body.type || !body.value) {
      return reply.code(400).send({ error: 'type and value are required' });
    }

    const maxItems = tierConfig[subscription.tier as BillingTier].features.maxWatchlistItems;

    try {
      const item = await watchlistService.addItem(
        subscription.id,
        body.type,
        body.value,
        maxItems
      );
      return reply.code(201).send({ item });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to add watchlist item';
      return reply.code(422).send({ error: message });
    }
  });

  // DELETE /darkwatch/watchlist/:id - Remove watchlist item
  fastify.delete('/watchlist/:id', async (request: FastifyRequest, reply: FastifyReply) => {
    const subscriptionId = await authed(request, reply);
    if (!subscriptionId) return;

    const id = (request.params as { id: string }).id;

    try {
      const item = await watchlistService.removeItem(id, subscriptionId);
      return reply.send({ item });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to remove watchlist item';
      return reply.code(422).send({ error: message });
    }
  });

  // POST /darkwatch/scan - Trigger on-demand scan
  fastify.post('/scan', async (request: FastifyRequest, reply: FastifyReply) => {
    const subscriptionId = await authed(request, reply);
    if (!subscriptionId) return;

    try {
      const job = await schedulerService.enqueueOnDemandScan(subscriptionId);
      return reply.send({
        job: {
          id: job?.id,
          status: 'queued',
        },
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to trigger scan';
      return reply.code(422).send({ error: message });
    }
  });

  // GET /darkwatch/scan/schedule - Get scan schedule
  fastify.get('/scan/schedule', async (request: FastifyRequest, reply: FastifyReply) => {
    const subscriptionId = await authed(request, reply);
    if (!subscriptionId) return;

    try {
      const schedule = await schedulerService.getScanSchedule(subscriptionId);
      return reply.send({ schedule });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to get schedule';
      return reply.code(500).send({ error: message });
    }
  });

  // GET /darkwatch/exposures - List exposures
  fastify.get('/exposures', async (request: FastifyRequest, reply: FastifyReply) => {
    const subscriptionId = await authed(request, reply);
    if (!subscriptionId) return;

    try {
      const exposures = await prisma.exposure.findMany({
        where: { subscriptionId },
        orderBy: { detectedAt: 'desc' },
        take: 50,
        include: {
          watchlistItem: true,
        },
      });
      return reply.send({ exposures });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to list exposures';
      return reply.code(500).send({ error: message });
    }
  });

  // GET /darkwatch/alerts - List alerts
  fastify.get('/alerts', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as FastifyRequest & { user?: { id: string } };
    const userId = authReq.user?.id;
    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    try {
      const alerts = await prisma.alert.findMany({
        where: { userId },
        orderBy: { createdAt: 'desc' },
        take: 50,
        include: {
          exposure: true,
        },
      });
      return reply.send({ alerts });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to list alerts';
      return reply.code(500).send({ error: message });
    }
  });

  // PATCH /darkwatch/alerts/:id/read - Mark alert as read
  fastify.patch('/alerts/:id/read', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as FastifyRequest & { user?: { id: string } };
    const userId = authReq.user?.id;
    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    const id = (request.params as { id: string }).id;

    try {
      const alert = await prisma.alert.update({
        where: { id },
        data: { isRead: true, readAt: new Date() },
      });
      return reply.send({ alert });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to mark alert as read';
      return reply.code(422).send({ error: message });
    }
  });

  // POST /darkwatch/webhook - External webhook receiver
  fastify.post('/webhook', async (request: FastifyRequest, reply: FastifyReply) => {
    const body = request.body as Record<string, unknown>;

    const source = typeof body.source === 'string' ? body.source : '';
    const identifier = typeof body.identifier === 'string' ? body.identifier : '';
    const identifierType = typeof body.identifierType === 'string' ? body.identifierType : '';
    const metadata = body.metadata as Record<string, unknown> | undefined;
    const timestamp = typeof body.timestamp === 'string' ? body.timestamp : new Date().toISOString();

    if (!source || !identifier || !identifierType) {
      return reply.code(400).send({
        error: 'source, identifier, and identifierType are required',
      });
    }

    const signature = request.headers['x-webhook-signature'] as string | undefined;
    const webhookTimestamp = request.headers['x-webhook-timestamp'] as string | undefined;

    if (!signature || !webhookTimestamp) {
      return reply.code(401).send({ error: 'Webhook signature and timestamp required' });
    }

    const valid = await webhookService.verifyWebhookSignature(
      JSON.stringify(body),
      signature,
      webhookTimestamp
    );
    if (!valid) {
      return reply.code(401).send({ error: 'Invalid webhook signature' });
    }

    try {
      const result = await webhookService.processExternalWebhook({
        source,
        identifier,
        identifierType,
        metadata,
        timestamp,
      });

      return reply.send({
        processed: true,
        exposuresCreated: result.exposuresCreated,
        alertsCreated: result.alertsCreated,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Webhook processing failed';
      console.error('[DarkWatch:Webhook] Error:', message);
      return reply.code(500).send({ error: 'Webhook processing failed' });
    }
  });

  // POST /darkwatch/scheduler/init - Initialize scheduled scans for all subscriptions
  fastify.post('/scheduler/init', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const jobsEnqueued = await schedulerService.scheduleSubscriptionScans();
      return reply.send({
        scheduled: jobsEnqueued.length,
        jobs: jobsEnqueued,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Scheduler init failed';
      return reply.code(500).send({ error: message });
    }
  });

  // POST /darkwatch/scheduler/reschedule - Reschedule all scans
  fastify.post('/scheduler/reschedule', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const jobsEnqueued = await schedulerService.rescheduleAll();
      return reply.send({
        rescheduled: jobsEnqueued.length,
        jobs: jobsEnqueued,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Scheduler reschedule failed';
      return reply.code(500).send({ error: message });
    }
  });
}
