import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../../prisma/prisma.service';
import { DealManager } from '../entities/deal/deal.manager';
import { FraudDetectionService, FraudCheckResult } from './fraud-detection.service';
import { FieldDetectorService } from './field-detector.service';
import { UserFieldsService } from './user-fields.service';
import { TimelineService } from './timeline.service';

export interface WebhookSubmission {
  token: string;
  body: Record<string, any>;
  headers: Record<string, string>;
  query: Record<string, string>;
  ip?: string;
}

export interface WebhookResult {
  success: boolean;
  dealId?: string;
  fraud?: FraudCheckResult;
  error?: string;
}

@Injectable()
export class WebhookProcessorService {
  private readonly logger = new Logger(WebhookProcessorService.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly dealManager: DealManager,
    private readonly fraudDetection: FraudDetectionService,
    private readonly fieldDetector: FieldDetectorService,
    private readonly userFields: UserFieldsService,
    private readonly timeline: TimelineService,
  ) {}

  /** Process webhook/token submission */
  async processWebhook(submission: WebhookSubmission): Promise<WebhookResult> {
    // 1. Validate token
    const endpoint = await this.prisma.crmWebhookEndpoint.findUnique({
      where: { token: submission.token },
    });
    if (!endpoint || !endpoint.isActive) {
      throw new NotFoundException('Webhook endpoint not found or inactive');
    }

    // 2. Merge body + query params
    const payload = { ...submission.query, ...submission.body };

    // 3. Anti-fraud check
    if (endpoint.antifraudEnabled) {
      const fraud = await this.fraudDetection.check({
        honeypot: payload.honeypot || payload._hp,
        formFilledMs: payload.formFilledMs ? Number(payload.formFilledMs) : undefined,
        email: payload.email || payload.mail,
        phone: payload.phone || payload.tel,
        fingerprint: payload.fingerprint,
        ip: submission.ip,
        userAgent: submission.headers['user-agent'],
      });

      if (fraud.action === 'spam') {
        this.logger.warn(`Webhook spam blocked: token=${submission.token}, score=${fraud.score}`);
        return { success: false, fraud, error: 'spam' };
      }

      if (fraud.action === 'captcha') {
        return { success: false, fraud, error: 'captcha_required' };
      }
    }

    // 4. Field detection
    const { fields, utm, analytics } = this.fieldDetector.detect(
      payload,
      endpoint.fieldMappings as Record<string, string> | null,
      endpoint.listMappings as Record<string, Record<string, string>> | null,
    );

    // 5. Build metadata
    const metadata: Record<string, any> = {
      utm: Object.keys(utm).length > 0 ? utm : undefined,
      analytics: Object.keys(analytics).length > 0 ? analytics : undefined,
      referer: submission.headers['referer'] || submission.headers['Referer'],
      ip: submission.ip,
      userAgent: submission.headers['user-agent'],
      fingerprint: payload.fingerprint,
      rawFields: Object.keys(fields.rawFields).length > 0 ? fields.rawFields : undefined,
      webhookId: endpoint.id,
      originalPayload: payload,
    };

    // 6. Create deal via DealManager (with full event lifecycle)
    const dealData: Record<string, any> = {
      clubId: endpoint.clubId,
      pipelineId: endpoint.pipelineId || undefined,
      stageId: endpoint.stageId || undefined,
      assigneeId: endpoint.defaultAssigneeId || undefined,
      title: fields.title || `Заявка: ${fields.contactName || fields.contactPhone || 'Без имени'}`,
      contactName: fields.contactName,
      contactPhone: fields.contactPhone,
      contactEmail: fields.contactEmail,
      source: 'WEBHOOK',
      metadata,
    };

    const deal = await this.dealManager.add(dealData, {
      skipPermissions: true,
      userId: endpoint.defaultAssigneeId || undefined,
    });

    // 7. Set custom field values
    if (Object.keys(fields.customFields).length > 0) {
      await this.userFields.setValuesForEntity(
        deal.id,
        'deal',
        endpoint.clubId,
        fields.customFields,
      );
    }

    // 8. Timeline entry for form submission
    await this.timeline.addEntry(deal.id, null, 'FORM_SUBMISSION', {
      subject: `Заявка с ${endpoint.name}`,
      metadata: {
        source: endpoint.name,
        utm,
        fields: {
          name: fields.contactName,
          phone: fields.contactPhone,
          email: fields.contactEmail,
        },
      },
    });

    this.logger.log(`Webhook processed: token=${submission.token}, dealId=${deal.id}`);

    return { success: true, dealId: deal.id };
  }

  /** Process landing form submission (simplified, with anti-fraud) */
  async processFormSubmission(
    body: Record<string, any>,
    ip?: string,
    userAgent?: string,
    referer?: string,
  ): Promise<WebhookResult> {
    // Anti-fraud
    const fraud = await this.fraudDetection.check({
      honeypot: body.honeypot,
      formFilledMs: body.formFilledMs ? Number(body.formFilledMs) : undefined,
      email: body.email,
      phone: body.phone,
      fingerprint: body.fingerprint,
      ip,
      userAgent,
    });

    if (fraud.action === 'spam') {
      this.logger.warn(`Form spam blocked: score=${fraud.score}`);
      return { success: false, fraud, error: 'spam' };
    }

    if (fraud.action === 'captcha') {
      return { success: false, fraud, error: 'captcha_required' };
    }

    // Extract UTM from body
    const utm: Record<string, string> = {};
    for (const key of ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']) {
      if (body[key]) utm[key.replace('utm_', '')] = body[key];
    }

    const metadata: Record<string, any> = {
      utm: Object.keys(utm).length > 0 ? utm : undefined,
      referer,
      ip,
      userAgent,
      fingerprint: body.fingerprint,
      source: body.source || 'landing',
      originalPayload: body,
    };

    const deal = await this.dealManager.add(
      {
        clubId: null, // platform level
        title: `Заявка: ${body.name || body.phone || 'С лендинга'}`,
        contactName: body.name,
        contactPhone: body.phone,
        contactEmail: body.email,
        source: 'FORM',
        metadata,
      },
      { skipPermissions: true },
    );

    await this.timeline.addEntry(deal.id, null, 'FORM_SUBMISSION', {
      subject: 'Заявка с лендинга',
      metadata: { utm, name: body.name, phone: body.phone, email: body.email },
    });

    return { success: true, dealId: deal.id };
  }
}
