import type { DltConfigModel, MessageTemplateModel } from '@zyphon/config-schema';
import type { NormalizedMessage } from '@zyphon/shared-types';

const HEADER_TXN = /^[A-Z]{6}$/;
const HEADER_PROMO = /^[0-9]{6}$/;

export function validatePeId(peId: string | undefined): { ok: boolean; message?: string } {
  if (!peId) {
    return { ok: false, message: 'Principal Entity ID (19 digits) is required for DLT SMS' };
  }
  if (!/^\d{19}$/.test(peId)) {
    return { ok: false, message: 'Principal Entity ID must be exactly 19 digits' };
  }
  return { ok: true };
}

export function validateHeaderForCategory(
  header: string | undefined,
  category: string,
): { ok: boolean; message?: string } {
  if (!header) {
    return { ok: false, message: 'DLT sender header is required' };
  }
  if (category === 'promotional') {
    if (!HEADER_PROMO.test(header)) {
      return { ok: false, message: 'Promotional DLT header must be exactly 6 digits' };
    }
  } else if (!HEADER_TXN.test(header) && !HEADER_PROMO.test(header)) {
    return {
      ok: false,
      message: 'DLT header must be 6 letters (transactional/service) or 6 digits (promotional)',
    };
  }
  return { ok: true };
}

export function normalizeIndianMobile(recipient: string, defaultCc = '91'): string {
  const digits = recipient.replace(/\D/g, '');
  if (digits.length === 10) {
    return `+${defaultCc}${digits}`;
  }
  if (digits.length === 12 && digits.startsWith('91')) {
    return `+${digits}`;
  }
  if (recipient.startsWith('+')) {
    return recipient;
  }
  return `+${digits}`;
}

export function isIndianMobile(recipient: string, defaultCc = '91'): boolean {
  const normalized = normalizeIndianMobile(recipient, defaultCc);
  return /^\+91[6-9]\d{9}$/.test(normalized);
}

function parseHm(hm: string): number {
  const parts = hm.split(':').map((x) => parseInt(x, 10));
  const h = parts[0] ?? 0;
  const m = parts[1] ?? 0;
  return h * 60 + m;
}

/** IST quiet hours for promotional SMS (default 21:00–09:00). */
export function isWithinPromotionalQuietHours(
  now: Date,
  dlt: DltConfigModel,
): boolean {
  if (!dlt.quiet_hours?.enabled) return false;
  const fmt = new Intl.DateTimeFormat('en-GB', {
    timeZone: dlt.quiet_hours.timezone || 'Asia/Kolkata',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  });
  const parts = fmt.formatToParts(now);
  const hour = parseInt(parts.find((p) => p.type === 'hour')?.value || '0', 10);
  const minute = parseInt(parts.find((p) => p.type === 'minute')?.value || '0', 10);
  const current = hour * 60 + minute;
  const start = parseHm(dlt.quiet_hours.start);
  const end = parseHm(dlt.quiet_hours.end);
  if (start > end) {
    return current >= start || current < end;
  }
  return current >= start && current < end;
}

export interface DltDispatchContext {
  dlt: DltConfigModel;
  template?: MessageTemplateModel;
  suppressions: string[];
  providerConfig?: Record<string, unknown>;
}

export function validateSmsDltDispatch(
  msg: NormalizedMessage,
  ctx: DltDispatchContext,
  now = new Date(),
): { ok: true } | { ok: false; code: 'VALIDATION_FAILED' | 'BLOCKED'; message: string } {
  const defaultCc =
    ctx.dlt.default_country_code ||
    (ctx.providerConfig?.country ? String(ctx.providerConfig.country) : '91');
  const normalizedTo = normalizeIndianMobile(msg.recipient, defaultCc);

  for (const blocked of ctx.suppressions) {
    const b = normalizeIndianMobile(blocked, defaultCc);
    if (b === normalizedTo) {
      return { ok: false, code: 'BLOCKED', message: 'Recipient is on the suppression list' };
    }
  }

  if (!isIndianMobile(msg.recipient, defaultCc)) {
    return { ok: true };
  }

  const provTemplateId = ctx.providerConfig?.template_id
    ? String(ctx.providerConfig.template_id)
    : undefined;
  const templateId =
    msg.content.template ||
    ctx.template?.dlt_id ||
    (msg.metadata?.dlt_template_id as string | undefined) ||
    provTemplateId;
  if (!templateId) {
    return {
      ok: false,
      code: 'VALIDATION_FAILED',
      message: 'DLT template ID is required for SMS to Indian numbers',
    };
  }

  const provPeId = ctx.providerConfig?.pe_id
    ? String(ctx.providerConfig.pe_id)
    : ctx.providerConfig?.entity_id
    ? String(ctx.providerConfig.entity_id)
    : undefined;
  const effectivePeId = ctx.dlt.pe_id || provPeId;

  const peCheck = validatePeId(effectivePeId);
  if (!peCheck.ok) {
    return { ok: false, code: 'VALIDATION_FAILED', message: peCheck.message! };
  }

  const category =
    ctx.template?.category ||
    (msg.metadata?.dlt_category as string | undefined) ||
    'transactional';
  const provHeader = ctx.providerConfig?.sender_id
    ? String(ctx.providerConfig.sender_id)
    : undefined;
  const header =
    ctx.template?.header ||
    (msg.metadata?.dlt_header as string | undefined) ||
    ctx.dlt.headers.find((h) => h.id === (msg.metadata?.dlt_header_id as string))?.header ||
    provHeader;

  const headerCheck = validateHeaderForCategory(header, category);
  if (!headerCheck.ok) {
    return { ok: false, code: 'VALIDATION_FAILED', message: headerCheck.message! };
  }

  const hasGlobalHeaders = Array.isArray(ctx.dlt.headers) && ctx.dlt.headers.length > 0;
  const registered = hasGlobalHeaders
    ? ctx.dlt.headers.some(
        (h) => h.header === header && (h.category === category || category === 'otp'),
      )
    : Boolean(provHeader && header === provHeader);

  if (!registered) {
    return {
      ok: false,
      code: 'VALIDATION_FAILED',
      message: 'Message header does not match a registered DLT header for this category',
    };
  }

  if (category === 'promotional' && isWithinPromotionalQuietHours(now, ctx.dlt)) {
    return {
      ok: false,
      code: 'VALIDATION_FAILED',
      message: 'Promotional SMS to Indian numbers is blocked during quiet hours (IST)',
    };
  }

  return { ok: true };
}
