/**
 * @ai-summary Controller for notifications API endpoints
 * @ai-context Handles requests for notification summary, templates, and sending
 */

import { FastifyRequest, FastifyReply } from 'fastify';
import { NotificationsService } from '../domain/notifications.service';
import type { TemplateKey } from '../domain/notifications.types';
import type {
  TemplateKeyParam,
  UpdateEmailTemplateRequest,
  PreviewTemplateRequest
} from './notifications.validation';

export class NotificationsController {
  private service: NotificationsService;

  constructor(service?: NotificationsService) {
    this.service = service || new NotificationsService();
  }

  // ========================
  // User Endpoints
  // ========================

  async getSummary(request: FastifyRequest, reply: FastifyReply) {
    const userId = request.user.sub;

    try {
      const summary = await this.service.getNotificationSummary(userId);
      return reply.code(200).send(summary);
    } catch (error) {
      request.log.error({ error }, 'Failed to get notification summary');
      return reply.code(500).send({
        error: 'Failed to get notification summary'
      });
    }
  }

  async getDueMaintenanceItems(request: FastifyRequest, reply: FastifyReply) {
    const userId = request.user.sub;

    try {
      const items = await this.service.getDueMaintenanceItems(userId);
      return reply.code(200).send(items);
    } catch (error) {
      request.log.error({ error }, 'Failed to get due maintenance items');
      return reply.code(500).send({
        error: 'Failed to get due maintenance items'
      });
    }
  }

  async getExpiringDocuments(request: FastifyRequest, reply: FastifyReply) {
    const userId = request.user.sub;

    try {
      const documents = await this.service.getExpiringDocuments(userId);
      return reply.code(200).send(documents);
    } catch (error) {
      request.log.error({ error }, 'Failed to get expiring documents');
      return reply.code(500).send({
        error: 'Failed to get expiring documents'
      });
    }
  }

  // ========================
  // In-App Notifications
  // ========================

  async getInAppNotifications(request: FastifyRequest, reply: FastifyReply) {
    const userId = request.user!.sub!;
    const query = request.query as { limit?: string; includeRead?: string };
    const limit = query.limit ? parseInt(query.limit, 10) : 20;
    const includeRead = query.includeRead === 'true';

    try {
      const notifications = await this.service.getUserNotifications(userId, limit, includeRead);
      return reply.send(notifications);
    } catch (error) {
      request.log.error({ error }, 'Failed to get in-app notifications');
      return reply.code(500).send({ error: 'Failed to get notifications' });
    }
  }

  async getUnreadCount(request: FastifyRequest, reply: FastifyReply) {
    const userId = request.user!.sub!;

    try {
      const count = await this.service.getUnreadCount(userId);
      return reply.send(count);
    } catch (error) {
      request.log.error({ error }, 'Failed to get unread count');
      return reply.code(500).send({ error: 'Failed to get unread count' });
    }
  }

  async markAsRead(request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply) {
    const userId = request.user!.sub!;
    const notificationId = request.params.id;

    try {
      const notification = await this.service.markAsRead(userId, notificationId);
      if (!notification) {
        return reply.code(404).send({ error: 'Notification not found' });
      }
      return reply.send(notification);
    } catch (error) {
      request.log.error({ error }, 'Failed to mark notification as read');
      return reply.code(500).send({ error: 'Failed to mark as read' });
    }
  }

  async markAllAsRead(request: FastifyRequest, reply: FastifyReply) {
    const userId = request.user!.sub!;

    try {
      const count = await this.service.markAllAsRead(userId);
      return reply.send({ markedAsRead: count });
    } catch (error) {
      request.log.error({ error }, 'Failed to mark all notifications as read');
      return reply.code(500).send({ error: 'Failed to mark all as read' });
    }
  }

  async deleteNotification(request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply) {
    const userId = request.user!.sub!;
    const notificationId = request.params.id;

    try {
      await this.service.deleteNotification(notificationId, userId);
      return reply.code(204).send();
    } catch (error) {
      request.log.error({ error }, 'Failed to delete notification');
      return reply.code(500).send({ error: 'Failed to delete notification' });
    }
  }

  // ========================
  // Admin Endpoints
  // ========================

  async listTemplates(request: FastifyRequest, reply: FastifyReply) {
    try {
      const templates = await this.service.listTemplates();
      return reply.code(200).send(templates);
    } catch (error) {
      request.log.error({ error }, 'Failed to list email templates');
      return reply.code(500).send({
        error: 'Failed to list email templates'
      });
    }
  }

  async getTemplate(
    request: FastifyRequest<{ Params: TemplateKeyParam }>,
    reply: FastifyReply
  ) {
    const { key } = request.params;

    try {
      const template = await this.service.getTemplate(key as TemplateKey);

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

      return reply.code(200).send(template);
    } catch (error) {
      request.log.error({ error }, 'Failed to get email template');
      return reply.code(500).send({
        error: 'Failed to get email template'
      });
    }
  }

  async updateTemplate(
    request: FastifyRequest<{
      Params: TemplateKeyParam;
      Body: UpdateEmailTemplateRequest;
    }>,
    reply: FastifyReply
  ) {
    const { key } = request.params;
    const updates = request.body;

    try {
      const template = await this.service.updateTemplate(key as TemplateKey, updates);

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

      return reply.code(200).send(template);
    } catch (error) {
      request.log.error({ error }, 'Failed to update email template');
      return reply.code(500).send({
        error: 'Failed to update email template'
      });
    }
  }

  async previewTemplate(
    request: FastifyRequest<{
      Params: TemplateKeyParam;
      Body: PreviewTemplateRequest;
    }>,
    reply: FastifyReply
  ) {
    const { subject, body, variables } = request.body;

    try {
      const preview = await this.service.previewTemplate(subject, body, variables);
      return reply.code(200).send(preview);
    } catch (error) {
      request.log.error({ error }, 'Failed to preview template');
      return reply.code(500).send({
        error: 'Failed to preview template'
      });
    }
  }

  async sendTestEmail(
    request: FastifyRequest<{ Params: TemplateKeyParam }>,
    reply: FastifyReply
  ) {
    const { key } = request.params;
    const userEmail = request.userContext?.email;
    const userName = request.userContext?.displayName || 'Test User';

    if (!userEmail) {
      return reply.code(400).send({
        error: 'No email address available. Please set your email in Settings.'
      });
    }

    try {
      const result = await this.service.sendTestEmail(
        key as any,
        userEmail,
        userName
      );

      if (!result.success) {
        return reply.code(500).send({
          error: result.error || 'Failed to send test email',
          subject: result.subject,
          body: result.body
        });
      }

      return reply.code(200).send({
        message: `Test email sent to ${userEmail}`,
        subject: result.subject,
        body: result.body
      });
    } catch (error) {
      request.log.error({ error }, 'Failed to send test email');
      return reply.code(500).send({
        error: 'Failed to send test email'
      });
    }
  }
}
