import { Request, Response, NextFunction, Router } from 'express';
import { WhatsAppService, MessageFilters, ContactFilters } from '../services/whatsapp.service';

export class WhatsAppController {
  public router: Router;

  constructor(private readonly whatsappService: WhatsAppService) {
    this.router = Router();
    this.initializeRoutes();
  }

  private initializeRoutes(): void {
    // Accounts
    this.router.get('/accounts', this.findAllAccounts.bind(this));
    this.router.get('/accounts/active', this.findActiveAccounts.bind(this));
    this.router.get('/accounts/:id', this.findAccount.bind(this));
    this.router.post('/accounts', this.createAccount.bind(this));
    this.router.patch('/accounts/:id', this.updateAccount.bind(this));
    this.router.patch('/accounts/:id/status', this.updateAccountStatus.bind(this));
    this.router.get('/accounts/:id/stats', this.getAccountStats.bind(this));

    // Contacts
    this.router.get('/accounts/:accountId/contacts', this.findContacts.bind(this));
    this.router.get('/contacts/:id', this.findContact.bind(this));
    this.router.get('/accounts/:accountId/contacts/phone/:phoneNumber', this.findContactByPhone.bind(this));
    this.router.post('/contacts', this.createContact.bind(this));
    this.router.patch('/contacts/:id', this.updateContact.bind(this));
    this.router.post('/contacts/:id/opt-in', this.optInContact.bind(this));
    this.router.post('/contacts/:id/opt-out', this.optOutContact.bind(this));
    this.router.post('/contacts/:id/tags', this.addTagToContact.bind(this));
    this.router.delete('/contacts/:id/tags/:tag', this.removeTagFromContact.bind(this));

    // Messages
    this.router.get('/accounts/:accountId/messages', this.findMessages.bind(this));
    this.router.get('/messages/:id', this.findMessage.bind(this));
    this.router.get('/contacts/:contactId/messages', this.findConversationMessages.bind(this));
    this.router.post('/messages', this.createMessage.bind(this));
    this.router.patch('/messages/:id/status', this.updateMessageStatus.bind(this));

    // Templates
    this.router.get('/accounts/:accountId/templates', this.findTemplates.bind(this));
    this.router.get('/accounts/:accountId/templates/approved', this.findApprovedTemplates.bind(this));
    this.router.get('/templates/:id', this.findTemplate.bind(this));
    this.router.post('/templates', this.createTemplate.bind(this));
    this.router.patch('/templates/:id', this.updateTemplate.bind(this));
    this.router.patch('/templates/:id/status', this.updateTemplateStatus.bind(this));
    this.router.delete('/templates/:id', this.deactivateTemplate.bind(this));
  }

  // ============================================
  // ACCOUNTS
  // ============================================

  private async findAllAccounts(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const accounts = await this.whatsappService.findAllAccounts(tenantId);
      res.json({ data: accounts, total: accounts.length });
    } catch (error) {
      next(error);
    }
  }

  private async findActiveAccounts(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const accounts = await this.whatsappService.findActiveAccounts(tenantId);
      res.json({ data: accounts, total: accounts.length });
    } catch (error) {
      next(error);
    }
  }

  private async findAccount(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const account = await this.whatsappService.findAccount(id);

      if (!account) {
        res.status(404).json({ error: 'Account not found' });
        return;
      }

      res.json({ data: account });
    } catch (error) {
      next(error);
    }
  }

  private async createAccount(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = req.headers['x-user-id'] as string;

      const account = await this.whatsappService.createAccount(tenantId, req.body, userId);
      res.status(201).json({ data: account });
    } catch (error) {
      next(error);
    }
  }

  private async updateAccount(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const account = await this.whatsappService.updateAccount(id, req.body);

      if (!account) {
        res.status(404).json({ error: 'Account not found' });
        return;
      }

      res.json({ data: account });
    } catch (error) {
      next(error);
    }
  }

  private async updateAccountStatus(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const { status } = req.body;

      const updated = await this.whatsappService.updateAccountStatus(id, status);

      if (!updated) {
        res.status(404).json({ error: 'Account not found' });
        return;
      }

      res.json({ data: { success: true } });
    } catch (error) {
      next(error);
    }
  }

  private async getAccountStats(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const startDate = new Date(req.query.startDate as string || Date.now() - 30 * 24 * 60 * 60 * 1000);
      const endDate = new Date(req.query.endDate as string || Date.now());

      const stats = await this.whatsappService.getAccountStats(id, startDate, endDate);
      res.json({ data: stats });
    } catch (error) {
      next(error);
    }
  }

  // ============================================
  // CONTACTS
  // ============================================

  private async findContacts(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { accountId } = req.params;
      const filters: ContactFilters = {
        conversationStatus: req.query.conversationStatus as string,
        tag: req.query.tag as string,
      };

      if (req.query.optedIn !== undefined) {
        filters.optedIn = req.query.optedIn === 'true';
      }

      const limit = parseInt(req.query.limit as string) || 50;

      const contacts = await this.whatsappService.findContacts(tenantId, accountId, filters, limit);
      res.json({ data: contacts, total: contacts.length });
    } catch (error) {
      next(error);
    }
  }

  private async findContact(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const contact = await this.whatsappService.findContact(id);

      if (!contact) {
        res.status(404).json({ error: 'Contact not found' });
        return;
      }

      res.json({ data: contact });
    } catch (error) {
      next(error);
    }
  }

  private async findContactByPhone(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { accountId, phoneNumber } = req.params;
      const contact = await this.whatsappService.findContactByPhone(accountId, phoneNumber);

      if (!contact) {
        res.status(404).json({ error: 'Contact not found' });
        return;
      }

      res.json({ data: contact });
    } catch (error) {
      next(error);
    }
  }

  private async createContact(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { accountId, ...data } = req.body;

      const contact = await this.whatsappService.createContact(tenantId, accountId, data);
      res.status(201).json({ data: contact });
    } catch (error) {
      next(error);
    }
  }

  private async updateContact(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const contact = await this.whatsappService.updateContact(id, req.body);

      if (!contact) {
        res.status(404).json({ error: 'Contact not found' });
        return;
      }

      res.json({ data: contact });
    } catch (error) {
      next(error);
    }
  }

  private async optInContact(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const optedIn = await this.whatsappService.optInContact(id);

      if (!optedIn) {
        res.status(404).json({ error: 'Contact not found' });
        return;
      }

      res.json({ data: { success: true } });
    } catch (error) {
      next(error);
    }
  }

  private async optOutContact(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const optedOut = await this.whatsappService.optOutContact(id);

      if (!optedOut) {
        res.status(404).json({ error: 'Contact not found' });
        return;
      }

      res.json({ data: { success: true } });
    } catch (error) {
      next(error);
    }
  }

  private async addTagToContact(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const { tag } = req.body;

      const contact = await this.whatsappService.addTagToContact(id, tag);

      if (!contact) {
        res.status(404).json({ error: 'Contact not found' });
        return;
      }

      res.json({ data: contact });
    } catch (error) {
      next(error);
    }
  }

  private async removeTagFromContact(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id, tag } = req.params;
      const contact = await this.whatsappService.removeTagFromContact(id, tag);

      if (!contact) {
        res.status(404).json({ error: 'Contact not found' });
        return;
      }

      res.json({ data: contact });
    } catch (error) {
      next(error);
    }
  }

  // ============================================
  // MESSAGES
  // ============================================

  private async findMessages(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { accountId } = req.params;
      const filters: MessageFilters = {
        contactId: req.query.contactId as string,
        direction: req.query.direction as string,
        messageType: req.query.messageType as string,
        status: req.query.status as string,
      };

      if (req.query.startDate) filters.startDate = new Date(req.query.startDate as string);
      if (req.query.endDate) filters.endDate = new Date(req.query.endDate as string);

      const limit = parseInt(req.query.limit as string) || 50;

      const messages = await this.whatsappService.findMessages(accountId, filters, limit);
      res.json({ data: messages, total: messages.length });
    } catch (error) {
      next(error);
    }
  }

  private async findMessage(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const message = await this.whatsappService.findMessage(id);

      if (!message) {
        res.status(404).json({ error: 'Message not found' });
        return;
      }

      res.json({ data: message });
    } catch (error) {
      next(error);
    }
  }

  private async findConversationMessages(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { contactId } = req.params;
      const limit = parseInt(req.query.limit as string) || 100;

      const messages = await this.whatsappService.findConversationMessages(contactId, limit);
      res.json({ data: messages, total: messages.length });
    } catch (error) {
      next(error);
    }
  }

  private async createMessage(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { accountId, contactId, ...data } = req.body;

      const message = await this.whatsappService.createMessage(tenantId, accountId, contactId, data);
      res.status(201).json({ data: message });
    } catch (error) {
      next(error);
    }
  }

  private async updateMessageStatus(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const { status, timestamp } = req.body;

      const message = await this.whatsappService.updateMessageStatus(
        id,
        status,
        timestamp ? new Date(timestamp) : undefined
      );

      if (!message) {
        res.status(404).json({ error: 'Message not found' });
        return;
      }

      res.json({ data: message });
    } catch (error) {
      next(error);
    }
  }

  // ============================================
  // TEMPLATES
  // ============================================

  private async findTemplates(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { accountId } = req.params;
      const category = req.query.category as string | undefined;

      const templates = await this.whatsappService.findTemplates(tenantId, accountId, category);
      res.json({ data: templates, total: templates.length });
    } catch (error) {
      next(error);
    }
  }

  private async findApprovedTemplates(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { accountId } = req.params;

      const templates = await this.whatsappService.findApprovedTemplates(tenantId, accountId);
      res.json({ data: templates, total: templates.length });
    } catch (error) {
      next(error);
    }
  }

  private async findTemplate(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const template = await this.whatsappService.findTemplate(id);

      if (!template) {
        res.status(404).json({ error: 'Template not found' });
        return;
      }

      res.json({ data: template });
    } catch (error) {
      next(error);
    }
  }

  private async createTemplate(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { accountId, ...data } = req.body;

      const template = await this.whatsappService.createTemplate(tenantId, accountId, data);
      res.status(201).json({ data: template });
    } catch (error) {
      next(error);
    }
  }

  private async updateTemplate(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const template = await this.whatsappService.updateTemplate(id, req.body);

      if (!template) {
        res.status(404).json({ error: 'Template not found' });
        return;
      }

      res.json({ data: template });
    } catch (error) {
      next(error);
    }
  }

  private async updateTemplateStatus(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const { metaStatus, metaTemplateId, rejectionReason } = req.body;

      const template = await this.whatsappService.updateTemplateStatus(
        id,
        metaStatus,
        metaTemplateId,
        rejectionReason
      );

      if (!template) {
        res.status(404).json({ error: 'Template not found' });
        return;
      }

      res.json({ data: template });
    } catch (error) {
      next(error);
    }
  }

  private async deactivateTemplate(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const deactivated = await this.whatsappService.deactivateTemplate(id);

      if (!deactivated) {
        res.status(404).json({ error: 'Template not found' });
        return;
      }

      res.status(204).send();
    } catch (error) {
      next(error);
    }
  }
}
