/**
 * Lead Capture Service
 * Embeddable forms, public submission, and multi-channel lead capture (WhatsApp, voice, social)
 */

import { logger } from '@/lib/logger';
import {
  leadsAdapter,
  leadCaptureFormsAdapter,
  leadNurtureSequencesAdapter,
  leadNurtureMembershipsAdapter,
} from '@/lib/adapters/leads';
import { createId } from '@paralleldrive/cuid2';
import type {
  CaptureFormInput,
  CaptureFormOutput,
  CaptureFormSubmission,
  CaptureFormField,
  CaptureFormStyling,
  LeadCaptureFormType,
  LeadOutput,
} from '@/lib/types/lead-crm.types';
/** JSON-compatible input value (replaces InputJsonValue) */
type InputJsonValue = string | number | boolean | null | InputJsonValue[] | { [key: string]: InputJsonValue };
/** Represents JSON null (replaces JsonNull) */
const JsonNull = null;
import { processEvent } from './lead-scoring.service';

const log = logger.scope('LeadCaptureService');

// ═══════════════════════════════════════════════════════════════════════
// Form CRUD
// ═══════════════════════════════════════════════════════════════════════

export async function getForms(userId: string): Promise<CaptureFormOutput[]> {
  const forms = await leadCaptureFormsAdapter.findMany({
    where: { userId },
    orderBy: { createdAt: 'desc' },
  });
  return forms.map(mapFormToOutput);
}

export async function createForm(userId: string, input: CaptureFormInput): Promise<CaptureFormOutput> {
  const id = createId();
  const form = await leadCaptureFormsAdapter.create({
    data: {
      id,
      userId,
      name: input.name,
      formType: input.formType as LeadCaptureFormType,
      fields: input.fields as unknown as InputJsonValue,
      styling: input.styling ? (input.styling as unknown as InputJsonValue) : JsonNull,
      embedCode: generateEmbedCodeString(id, input.formType),
    },
  });

  log.info('Capture form created', { formId: form.id, userId });
  return mapFormToOutput(form);
}

export async function updateForm(userId: string, formId: string, input: Partial<CaptureFormInput>): Promise<CaptureFormOutput | null> {
  const existing = await leadCaptureFormsAdapter.findFirst({ where: { id: formId, userId } });
  if (!existing) return null;

  const updateData: Record<string, unknown> = {};
  if (input.name !== undefined) updateData.name = input.name;
  if (input.formType !== undefined) updateData.formType = input.formType as LeadCaptureFormType;
  if (input.fields !== undefined) updateData.fields = input.fields as unknown as InputJsonValue;
  if (input.styling !== undefined) updateData.styling = input.styling ? (input.styling as unknown as InputJsonValue) : JsonNull;

  const form = await leadCaptureFormsAdapter.update({
    where: { id: formId },
    data: updateData,
  });

  return mapFormToOutput(form);
}

export async function deleteForm(userId: string, formId: string): Promise<boolean> {
  const existing = await leadCaptureFormsAdapter.findFirst({ where: { id: formId, userId } });
  if (!existing) return false;

  await leadCaptureFormsAdapter.delete({ where: { id: formId } });
  return true;
}

export async function getFormById(formId: string): Promise<CaptureFormOutput | null> {
  const form = await leadCaptureFormsAdapter.findUnique({ where: { id: formId } });
  if (!form || !form.isActive) return null;
  return mapFormToOutput(form);
}

// ═══════════════════════════════════════════════════════════════════════
// Public Form Submission
// ═══════════════════════════════════════════════════════════════════════

export async function submitForm(submission: CaptureFormSubmission): Promise<LeadOutput> {
  const form = await leadCaptureFormsAdapter.findUnique({ where: { id: submission.formId } });
  if (!form || !form.isActive) throw new Error('Form not found or inactive');

  const fields = form.fields as unknown as CaptureFormField[];
  const data = submission.data;

  // Validate required fields
  for (const field of fields) {
    if (field.required && !data[field.name]) {
      throw new Error(`Missing required field: ${field.label}`);
    }
  }

  // Create lead from submission
  const leadId = createId();
  const now = new Date();

  const lead = await leadsAdapter.create({
    data: {
      id: leadId,
      userId: form.userId,
      name: data.name || data.full_name || 'Unknown',
      phone: data.phone || data.telephone || null,
      email: data.email || null,
      company: data.company || data.business || null,
      source: 'capture_form',
      sourceChannel: submission.sourceChannel ?? form.formType,
      interest: data.interest || data.service || null,
      notes: data.notes || data.message || null,
      customFields: data as unknown as InputJsonValue,
      metadata: (submission.metadata ?? {}) as InputJsonValue,
      captureFormId: form.id,
      tags: [],
      language: (data.language as 'ar' | 'en') ?? 'en',
      firstTouchAt: now,
      lastActivityAt: now,
      touchCount: 1,
      updatedAt: now,
    },
    include: { pipelineStage: true },
  });

  // Increment form submissions
  await leadCaptureFormsAdapter.update({
    where: { id: form.id },
    data: { submissions: { increment: 1 } },
  });

  // Trigger scoring event
  try {
    await processEvent(leadId, 'form_submit', { formId: form.id, formName: form.name });
  } catch (scoringError) {
    log.warn('Scoring event failed after form submission', { leadId, error: String(scoringError) });
  }

  // Check nurture enrollment (ON_CAPTURE trigger)
  try {
    const sequences = await leadNurtureSequencesAdapter.findMany({
      where: { userId: form.userId, isActive: true, triggerType: 'ON_CAPTURE' },
      include: { steps: { orderBy: { stepOrder: 'asc' }, take: 1 } },
    });

    for (const seq of sequences) {
      const firstStep = (seq as any).steps?.[0];
      const nextActionAt = firstStep
        ? new Date(Date.now() + firstStep.delayHours * 60 * 60 * 1000)
        : null;

      await leadNurtureMembershipsAdapter.create({
        data: {
          id: createId(),
          leadId,
          sequenceId: seq.id,
          status: 'ACTIVE',
          nextActionAt,
        },
      });

      await leadNurtureSequencesAdapter.update({
        where: { id: seq.id },
        data: { enrolledCount: { increment: 1 } },
      });
    }
  } catch (nurtureError) {
    log.warn('Auto-nurture enrollment failed', { leadId, error: String(nurtureError) });
  }

  log.info('Form submitted, lead created', { leadId, formId: form.id });
  return mapLeadOutput(lead);
}

// ═══════════════════════════════════════════════════════════════════════
// Embed Code
// ═══════════════════════════════════════════════════════════════════════

export function generateEmbedCode(formId: string): { iframe: string; script: string } {
  const baseUrl = process.env.NEXTAUTH_URL || process.env.NEXT_PUBLIC_APP_URL || 'https://mawidi.com';
  const iframeSrc = `${baseUrl}/embed/lead-form/${formId}`;

  return {
    iframe: `<iframe src="${iframeSrc}" width="100%" height="500" frameborder="0" style="border: none; border-radius: 8px;"></iframe>`,
    script: `<div id="mawidi-lead-form-${formId}"></div>\n<script src="${baseUrl}/embed/lead-form.js" data-form-id="${formId}" async></script>`,
  };
}

// ═══════════════════════════════════════════════════════════════════════
// Multi-Channel Capture
// ═══════════════════════════════════════════════════════════════════════

export async function captureFromWhatsApp(
  userId: string,
  conversationData: { name?: string; phone: string; message?: string; metadata?: Record<string, unknown> },
): Promise<string> {
  const leadId = createId();
  const now = new Date();

  await leadsAdapter.create({
    data: {
      id: leadId,
      userId,
      name: conversationData.name || 'WhatsApp Lead',
      phone: conversationData.phone,
      source: 'whatsapp',
      sourceChannel: 'whatsapp',
      notes: conversationData.message ?? null,
      metadata: (conversationData.metadata ?? {}) as InputJsonValue,
      customFields: {} as InputJsonValue,
      tags: [],
      firstTouchAt: now,
      lastActivityAt: now,
      touchCount: 1,
      updatedAt: now,
    },
  });

  try {
    await processEvent(leadId, 'whatsapp_message');
  } catch { /* non-blocking */ }

  log.info('Lead captured from WhatsApp', { leadId, userId });
  return leadId;
}

export async function captureFromVoiceAgent(
  userId: string,
  callData: { name?: string; phone?: string; summary?: string; metadata?: Record<string, unknown> },
): Promise<string> {
  const leadId = createId();
  const now = new Date();

  await leadsAdapter.create({
    data: {
      id: leadId,
      userId,
      name: callData.name || 'Voice Lead',
      phone: callData.phone ?? null,
      source: 'voice_agent',
      sourceChannel: 'voice',
      notes: callData.summary ?? null,
      metadata: (callData.metadata ?? {}) as InputJsonValue,
      customFields: {} as InputJsonValue,
      tags: [],
      firstTouchAt: now,
      lastActivityAt: now,
      touchCount: 1,
      updatedAt: now,
    },
  });

  try {
    await processEvent(leadId, 'voice_call');
  } catch { /* non-blocking */ }

  log.info('Lead captured from voice agent', { leadId, userId });
  return leadId;
}

export async function captureFromSocial(
  userId: string,
  socialData: { name?: string; email?: string; platform: string; profileUrl?: string; metadata?: Record<string, unknown> },
): Promise<string> {
  const leadId = createId();
  const now = new Date();

  await leadsAdapter.create({
    data: {
      id: leadId,
      userId,
      name: socialData.name || 'Social Lead',
      email: socialData.email ?? null,
      source: 'social',
      sourceChannel: socialData.platform,
      metadata: ({ profileUrl: socialData.profileUrl, ...(socialData.metadata ?? {}) }) as InputJsonValue,
      customFields: {} as InputJsonValue,
      tags: [],
      firstTouchAt: now,
      lastActivityAt: now,
      touchCount: 1,
      updatedAt: now,
    },
  });

  log.info('Lead captured from social', { leadId, userId, platform: socialData.platform });
  return leadId;
}

// ═══════════════════════════════════════════════════════════════════════
// Helpers
// ═══════════════════════════════════════════════════════════════════════

function generateEmbedCodeString(formId: string, _formType: string): string {
  const baseUrl = process.env.NEXTAUTH_URL || process.env.NEXT_PUBLIC_APP_URL || 'https://mawidi.com';
  return `<iframe src="${baseUrl}/embed/lead-form/${formId}" width="100%" height="500" frameborder="0"></iframe>`;
}

function mapFormToOutput(form: Record<string, unknown>): CaptureFormOutput {
  const f = form as Record<string, unknown>;
  return {
    id: f.id as string,
    userId: f.userId as string,
    name: f.name as string,
    formType: f.formType as LeadCaptureFormType,
    fields: f.fields as CaptureFormField[],
    styling: (f.styling as CaptureFormStyling) ?? null,
    embedCode: (f.embedCode as string) ?? null,
    isActive: f.isActive as boolean,
    submissions: f.submissions as number,
    createdAt: f.createdAt as Date,
    updatedAt: f.updatedAt as Date,
  };
}

function mapLeadOutput(lead: Record<string, unknown>): LeadOutput {
  const l = lead as Record<string, unknown>;
  // Re-use lightweight mapping from lead-crm service pattern
  const { getLeadGrade } = require('@/lib/types/lead-crm.types');
  return {
    id: l.id as string,
    userId: l.userId as string,
    organizationId: (l.organizationId as string) ?? null,
    name: l.name as string,
    phone: (l.phone as string) ?? null,
    email: (l.email as string) ?? null,
    company: (l.company as string) ?? null,
    source: l.source as string,
    campaignId: (l.campaignId as string) ?? null,
    interest: (l.interest as string) ?? null,
    notes: (l.notes as string) ?? null,
    customFields: (l.customFields as Record<string, unknown>) ?? {},
    metadata: (l.metadata as Record<string, unknown>) ?? {},
    status: l.status as string,
    score: (l.score as number) ?? 0,
    convertedAt: (l.convertedAt as Date) ?? null,
    lastContactAt: (l.lastContactAt as Date) ?? null,
    assignedTo: (l.assignedTo as string) ?? null,
    pipelineStageId: (l.pipelineStageId as string) ?? null,
    dealValue: (l.dealValue as number) ?? null,
    dealCurrency: (l.dealCurrency as string) ?? null,
    expectedCloseAt: (l.expectedCloseAt as Date) ?? null,
    lostReason: (l.lostReason as string) ?? null,
    qualifiedAt: (l.qualifiedAt as Date) ?? null,
    qualificationScore: (l.qualificationScore as number) ?? null,
    tags: (l.tags as string[]) ?? [],
    language: (l.language as string) ?? null,
    captureFormId: (l.captureFormId as string) ?? null,
    sourceChannel: (l.sourceChannel as string) ?? null,
    firstTouchAt: (l.firstTouchAt as Date) ?? null,
    lastActivityAt: (l.lastActivityAt as Date) ?? null,
    touchCount: (l.touchCount as number) ?? 0,
    createdAt: l.createdAt as Date,
    updatedAt: l.updatedAt as Date,
    grade: getLeadGrade((l.score as number) ?? 0),
  };
}
