import { Request } from 'express';
import { ClaimInvoice } from '../models/ClaimInvoice';
import { ClaimCreditNote } from '../models/ClaimCreditNote';
import { WorkflowRequest } from '../models/WorkflowRequest';
import { ApprovalLevel } from '../models/ApprovalLevel';
import { DealerClaimDetails } from '../models/DealerClaimDetails';
import { User } from '../models/User';
import { ApprovalService } from './approval.service';
import logger from '../utils/logger';
import crypto from 'crypto';
import { activityService } from './activity.service';
import { notificationService } from './notification.service';

/**
 * DMS Webhook Service
 * Handles processing of webhook callbacks from DMS system
 */
export class DMSWebhookService {
  private webhookSecret: string;
  private approvalService: ApprovalService;

  constructor() {
    this.webhookSecret = process.env.DMS_WEBHOOK_SECRET || '';
    this.approvalService = new ApprovalService();
  }

  /**
   * Validate webhook signature for security
   * DMS should send a signature in the header that we can verify
   */
  async validateWebhookSignature(req: Request): Promise<boolean> {
    // If webhook secret is not configured, skip validation (for development)
    if (!this.webhookSecret) {
      logger.warn('[DMSWebhook] Webhook secret not configured, skipping signature validation');
      return true;
    }

    try {
      const signature = req.headers['x-dms-signature'] as string;
      if (!signature) {
        logger.warn('[DMSWebhook] Missing webhook signature in header');
        return false;
      }

      // Create HMAC hash of the request body
      const body = JSON.stringify(req.body);
      const expectedSignature = crypto
        .createHmac('sha256', this.webhookSecret)
        .update(body)
        .digest('hex');

      // Compare signatures (use constant-time comparison to prevent timing attacks)
      const isValid = crypto.timingSafeEqual(
        Buffer.from(signature),
        Buffer.from(expectedSignature)
      );

      if (!isValid) {
        logger.warn('[DMSWebhook] Invalid webhook signature');
      }

      return isValid;
    } catch (error) {
      logger.error('[DMSWebhook] Error validating webhook signature:', error);
      return false;
    }
  }

  /**
   * Process invoice generation webhook from DMS
   */
  async processInvoiceWebhook(payload: any): Promise<{
    success: boolean;
    invoiceNumber?: string;
    error?: string;
  }> {
    try {
      // Validate required fields
      const requiredFields = ['request_number', 'document_no', 'document_type'];
      for (const field of requiredFields) {
        if (!payload[field]) {
          return {
            success: false,
            error: `Missing required field: ${field}`,
          };
        }
      }

      // Find workflow request by request number
      const request = await WorkflowRequest.findOne({
        where: {
          requestNumber: payload.request_number,
        },
      });

      if (!request) {
        return {
          success: false,
          error: `Request not found: ${payload.request_number}`,
        };
      }

      // Find or create invoice record
      let invoice = await ClaimInvoice.findOne({
        where: { requestId: request.requestId },
      });

      // Create invoice if it doesn't exist (new flow: webhook creates invoice)
      if (!invoice) {
        logger.info('[DMSWebhook] Invoice record not found, creating new invoice from webhook', {
          requestNumber: payload.request_number,
        });

        invoice = await ClaimInvoice.create({
          requestId: request.requestId,
          invoiceNumber: payload.document_no,
          dmsNumber: payload.document_no,
          invoiceDate: payload.document_date ? new Date(payload.document_date) : new Date(),
          amount: payload.total_amount || payload.claim_amount,
          status: 'GENERATED',
          generatedAt: new Date(),
          filePath: payload.invoice_file_path || null,
          errorMessage: payload.error_message || null,
          description: this.buildInvoiceDescription(payload),
        });

        logger.info('[DMSWebhook] Invoice created successfully from webhook', {
          requestNumber: payload.request_number,
          invoiceNumber: payload.document_no,
        });
      } else {
        // Update existing invoice with DMS response data
        await invoice.update({
          invoiceNumber: payload.document_no,
          dmsNumber: payload.document_no, // DMS document number
          invoiceDate: payload.document_date ? new Date(payload.document_date) : new Date(),
          amount: payload.total_amount || payload.claim_amount,
          status: 'GENERATED',
          generatedAt: new Date(),
          filePath: payload.invoice_file_path || null,
          errorMessage: payload.error_message || null,
          // Store additional DMS data in description or separate fields if needed
          description: this.buildInvoiceDescription(payload),
        });

        logger.info('[DMSWebhook] Invoice updated successfully', {
          requestNumber: payload.request_number,
          invoiceNumber: payload.document_no,
          irnNo: payload.irn_no,
        });
      }

      // Auto-approve Step 7 and move to Step 8
      await this.logEInvoiceGenerationActivity(request.requestId, payload.request_number);

      return {
        success: true,
        invoiceNumber: payload.document_no,
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      logger.error('[DMSWebhook] Error processing invoice webhook:', error);
      return {
        success: false,
        error: errorMessage,
      };
    }
  }

  /**
   * Process credit note generation webhook from DMS
   */
  async processCreditNoteWebhook(payload: any): Promise<{
    success: boolean;
    creditNoteNumber?: string;
    error?: string;
  }> {
    try {
      // Validate required fields
      const requiredFields = ['request_number', 'document_no', 'document_type'];
      for (const field of requiredFields) {
        if (!payload[field]) {
          return {
            success: false,
            error: `Missing required field: ${field}`,
          };
        }
      }

      // Find workflow request by request number
      const request = await WorkflowRequest.findOne({
        where: {
          requestNumber: payload.request_number,
        },
      });

      if (!request) {
        return {
          success: false,
          error: `Request not found: ${payload.request_number}`,
        };
      }

      // Find invoice to link credit note (optional - credit note can exist without invoice)
      const invoice = await ClaimInvoice.findOne({
        where: { requestId: request.requestId },
      });

      // Find or create credit note record
      let creditNote = await ClaimCreditNote.findOne({
        where: { requestId: request.requestId },
      });

      // Create credit note if it doesn't exist (new flow: webhook creates credit note)
      if (!creditNote) {
        logger.info('[DMSWebhook] Credit note record not found, creating new credit note from webhook', {
          requestNumber: payload.request_number,
          hasInvoice: !!invoice,
        });

        creditNote = await ClaimCreditNote.create({
          requestId: request.requestId,
          invoiceId: invoice?.invoiceId || undefined, // Allow undefined if no invoice exists
          creditNoteNumber: payload.document_no,
          creditNoteDate: payload.document_date ? new Date(payload.document_date) : new Date(),
          creditNoteAmount: payload.total_amount || payload.credit_amount,
          sapDocumentNumber: payload.sap_credit_note_no || null,
          status: 'CONFIRMED',
          confirmedAt: new Date(),
          creditNoteFilePath: payload.credit_note_file_path || null,
          errorMessage: payload.error_message || null,
          description: this.buildCreditNoteDescription(payload),
        });

        logger.info('[DMSWebhook] Credit note created successfully from webhook', {
          requestNumber: payload.request_number,
          creditNoteNumber: payload.document_no,
          hasInvoice: !!invoice,
        });

        // Log activity and notify initiator
        await this.logCreditNoteCreationActivity(
          request.requestId,
          payload.request_number,
          payload.document_no,
          creditNote.creditNoteAmount || payload.total_amount || payload.credit_amount
        );
      } else {
        // Update existing credit note with DMS response data
        await creditNote.update({
          invoiceId: invoice?.invoiceId || creditNote.invoiceId, // Preserve existing invoiceId if no invoice found
          creditNoteNumber: payload.document_no,
          creditNoteDate: payload.document_date ? new Date(payload.document_date) : new Date(),
          creditNoteAmount: payload.total_amount || payload.credit_amount,
          sapDocumentNumber: payload.sap_credit_note_no || null,
          status: 'CONFIRMED',
          confirmedAt: new Date(),
          creditNoteFilePath: payload.credit_note_file_path || null,
          errorMessage: payload.error_message || null,
          description: this.buildCreditNoteDescription(payload),
        });

        logger.info('[DMSWebhook] Credit note updated successfully', {
          requestNumber: payload.request_number,
          creditNoteNumber: payload.document_no,
          sapCreditNoteNo: payload.sap_credit_note_no,
          irnNo: payload.irn_no,
          hasInvoice: !!invoice,
        });

        // Log activity and notify initiator for updated credit note
        await this.logCreditNoteCreationActivity(
          request.requestId,
          payload.request_number,
          payload.document_no,
          creditNote.creditNoteAmount || payload.total_amount || payload.credit_amount
        );
      }

      return {
        success: true,
        creditNoteNumber: payload.document_no,
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      logger.error('[DMSWebhook] Error processing credit note webhook:', error);
      return {
        success: false,
        error: errorMessage,
      };
    }
  }

  /**
   * Build invoice description from DMS payload
   */
  private buildInvoiceDescription(payload: any): string {
    const parts: string[] = [];

    if (payload.irn_no) {
      parts.push(`IRN: ${payload.irn_no}`);
    }
    if (payload.item_code_no) {
      parts.push(`Item Code: ${payload.item_code_no}`);
    }
    if (payload.hsn_sac_code) {
      parts.push(`HSN/SAC: ${payload.hsn_sac_code}`);
    }
    if (payload.cgst_amount || payload.sgst_amount || payload.igst_amount) {
      parts.push(`GST - CGST: ${payload.cgst_amount || 0}, SGST: ${payload.sgst_amount || 0}, IGST: ${payload.igst_amount || 0}`);
    }

    return parts.length > 0 ? parts.join(' | ') : '';
  }

  /**
   * Build credit note description from DMS payload
   */
  private buildCreditNoteDescription(payload: any): string {
    const parts: string[] = [];

    if (payload.irn_no) {
      parts.push(`IRN: ${payload.irn_no}`);
    }
    if (payload.sap_credit_note_no) {
      parts.push(`SAP CN: ${payload.sap_credit_note_no}`);
    }
    if (payload.credit_type) {
      parts.push(`Credit Type: ${payload.credit_type}`);
    }
    if (payload.item_code_no) {
      parts.push(`Item Code: ${payload.item_code_no}`);
    }
    if (payload.hsn_sac_code) {
      parts.push(`HSN/SAC: ${payload.hsn_sac_code}`);
    }
    if (payload.cgst_amount || payload.sgst_amount || payload.igst_amount) {
      parts.push(`GST - CGST: ${payload.cgst_amount || 0}, SGST: ${payload.sgst_amount || 0}, IGST: ${payload.igst_amount || 0}`);
    }

    return parts.length > 0 ? parts.join(' | ') : '';
  }

  /**
   * Log Credit Note Creation as activity and notify initiator
   * This is called after credit note is created/updated from DMS webhook
   */
  private async logCreditNoteCreationActivity(
    requestId: string,
    requestNumber: string,
    creditNoteNumber: string,
    creditNoteAmount: number
  ): Promise<void> {
    try {
      // Check if this is a claim management workflow
      const request = await WorkflowRequest.findByPk(requestId);
      if (!request) {
        logger.warn('[DMSWebhook] Request not found for credit note activity logging', { requestId });
        return;
      }

      const workflowType = (request as any).workflowType;
      if (workflowType !== 'CLAIM_MANAGEMENT') {
        logger.info('[DMSWebhook] Not a claim management workflow, skipping credit note activity logging', {
          requestId,
          workflowType,
        });
        return;
      }

      const initiatorId = (request as any).initiatorId;
      if (!initiatorId) {
        logger.warn('[DMSWebhook] Initiator ID not found for credit note notification', { requestId });
        return;
      }

      // Log activity
      await activityService.log({
        requestId,
        type: 'status_change',
        user: undefined, // System event (no user means it's a system event)
        timestamp: new Date().toISOString(),
        action: 'Credit Note Generated',
        details: `Credit note generated from DMS. Credit Note Number: ${creditNoteNumber}. Credit Note Amount: ₹${creditNoteAmount || 0}. Request: ${requestNumber}`,
        category: 'credit_note',
        severity: 'INFO',
      });

      logger.info('[DMSWebhook] Credit note activity logged successfully', {
        requestId,
        requestNumber,
        creditNoteNumber,
      });

      // Get dealer information from claim details
      const claimDetails = await DealerClaimDetails.findOne({
        where: { requestId }
      });

      let dealerUserId: string | null = null;
      if (claimDetails?.dealerEmail) {
        const dealerUser = await User.findOne({
          where: { email: claimDetails.dealerEmail.toLowerCase() },
          attributes: ['userId'],
        });
        dealerUserId = dealerUser?.userId || null;

        if (dealerUserId) {
          logger.info('[DMSWebhook] Found dealer user for notification', {
            requestId,
            dealerEmail: claimDetails.dealerEmail,
            dealerUserId,
          });
        } else {
          logger.warn('[DMSWebhook] Dealer email found but user not found in system', {
            requestId,
            dealerEmail: claimDetails.dealerEmail,
          });
        }
      } else {
        logger.info('[DMSWebhook] No dealer email found in claim details', { requestId });
      }

      // Send notification to initiator
      await notificationService.sendToUsers([initiatorId], {
        title: 'Credit Note Generated',
        body: `Credit note ${creditNoteNumber} has been generated for request ${requestNumber}. Amount: ₹${creditNoteAmount || 0}`,
        requestId,
        requestNumber,
        url: `/request/${requestNumber}`,
        type: 'status_change',
        priority: 'MEDIUM',
        actionRequired: false,
        metadata: {
          creditNoteNumber,
          creditNoteAmount,
          source: 'dms_webhook',
        },
      });

      logger.info('[DMSWebhook] Credit note notification sent to initiator', {
        requestId,
        requestNumber,
        initiatorId,
        creditNoteNumber,
      });

      // Send notification to dealer if dealer user exists
      if (dealerUserId) {
        await notificationService.sendToUsers([dealerUserId], {
          title: 'Credit Note Generated',
          body: `Credit note ${creditNoteNumber} has been generated for your claim request ${requestNumber}. Amount: ₹${creditNoteAmount || 0}`,
          requestId,
          requestNumber,
          url: `/request/${requestNumber}`,
          type: 'status_change',
          priority: 'MEDIUM',
          actionRequired: false,
          metadata: {
            creditNoteNumber,
            creditNoteAmount,
            source: 'dms_webhook',
            recipient: 'dealer',
          },
        });

        logger.info('[DMSWebhook] Credit note notification sent to dealer', {
          requestId,
          requestNumber,
          dealerUserId,
          dealerEmail: claimDetails?.dealerEmail,
          creditNoteNumber,
        });
      }
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      logger.error('[DMSWebhook] Error logging credit note activity:', {
        requestId,
        requestNumber,
        error: errorMessage,
      });
      // Don't throw error - webhook processing should continue even if activity/notification fails
      // The credit note is already created/updated, which is the primary goal
    }
  }

  /**
   * Log E-Invoice Generation as activity (no longer an approval step)
   * This is called after invoice is created/updated from DMS webhook
   */
  private async logEInvoiceGenerationActivity(requestId: string, requestNumber: string): Promise<void> {
    try {
      // Check if this is a claim management workflow
      const request = await WorkflowRequest.findByPk(requestId);
      if (!request) {
        logger.warn('[DMSWebhook] Request not found for Step 7 auto-approval', { requestId });
        return;
      }

      const workflowType = (request as any).workflowType;
      if (workflowType !== 'CLAIM_MANAGEMENT') {
        logger.info('[DMSWebhook] Not a claim management workflow, skipping Step 7 auto-approval', {
          requestId,
          workflowType,
        });
        return;
      }

      // E-Invoice Generation is now an activity log only, not an approval step
      // Log the activity using the dealerClaimService
      const { DealerClaimService } = require('./dealerClaim.service');
      const dealerClaimService = new DealerClaimService();
      const invoice = await ClaimInvoice.findOne({ where: { requestId } });
      const invoiceNumber = invoice?.invoiceNumber || 'N/A';

      await dealerClaimService.logEInvoiceGenerationActivity(requestId, invoiceNumber);

      logger.info('[DMSWebhook] E-Invoice Generation activity logged successfully', {
        requestId,
        requestNumber,
        invoiceNumber,
      });
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      logger.error('[DMSWebhook] Error logging E-Invoice Generation activity:', {
        requestId,
        requestNumber,
        error: errorMessage,
      });
      // Don't throw error - webhook processing should continue even if activity logging fails
      // The invoice is already created/updated, which is the primary goal
    }
  }
}

