import crypto from 'crypto';

const DEFAULT_TIKTOK_PIXEL_CODE = 'D7CKLEBC77UCDU0QMSCG';
const TIKTOK_EVENT_TRACK_URL = 'https://business-api.tiktok.com/open_api/v1.3/event/track/';

export type TikTokWebEventInput = {
  email?: string | null;
  event: string;
  description?: string | null;
  eventId?: string | null;
  eventTime?: number | null;
  externalId?: string | null;
  ip?: string | null;
  properties?: Record<string, unknown> | null;
  referrer?: string | null;
  ttclid?: string | null;
  ttp?: string | null;
  url?: string | null;
  userAgent?: string | null;
};

export type TikTokLeadEventInput = Omit<TikTokWebEventInput, 'event' | 'properties' | 'eventTime'> & {
  description?: string | null;
  status?: string | null;
};

function getTikTokAccessToken(): string {
  return (process.env.TIKTOK_ACCESS_TOKEN || process.env.TIKTOK_EVENTS_API_ACCESS_TOKEN || '').trim();
}

function getTikTokPixelCode(): string {
  return (
    process.env.TIKTOK_PIXEL_CODE
    || process.env.NEXT_PUBLIC_TIKTOK_PIXEL_ID
    || DEFAULT_TIKTOK_PIXEL_CODE
  ).trim();
}

function normalizeText(value: string | null | undefined): string | null {
  if (typeof value !== 'string') return null;
  const normalized = value.trim();
  return normalized || null;
}

function normalizeEmail(value: string): string {
  return value.trim().toLowerCase();
}

function hashValue(value: string | null | undefined): string | null {
  const normalized = normalizeText(value);
  if (!normalized) return null;
  return crypto.createHash('sha256').update(normalized).digest('hex');
}

function pruneObject<T>(value: T): T {
  if (Array.isArray(value)) {
    return value
      .map((entry) => pruneObject(entry))
      .filter((entry) => entry !== null && entry !== undefined) as T;
  }

  if (value && typeof value === 'object') {
    return Object.fromEntries(
      Object.entries(value as Record<string, unknown>)
        .map(([key, entry]) => [key, pruneObject(entry)])
        .filter(([, entry]) => entry !== null && entry !== undefined && entry !== '')
    ) as T;
  }

  return value;
}

function buildEventId(value: string | null | undefined): string {
  return normalizeText(value) || `rm_event_${crypto.randomUUID()}`;
}

export async function trackTikTokWebEvent(input: TikTokWebEventInput): Promise<void> {
  const accessToken = getTikTokAccessToken();
  const pixelCode = getTikTokPixelCode();
  if (!accessToken || !pixelCode) return;

  const email = normalizeText(input.email);
  const normalizedEmail = email ? normalizeEmail(email) : null;
  const normalizedExternalId = normalizeText(input.externalId);
  if (!normalizedEmail && !normalizedExternalId) return;
  if (normalizedEmail && !normalizedEmail.includes('@')) return;

  const payload = pruneObject({
    event_source_id: pixelCode,
    event_source: 'web',
    test_event_code: normalizeText(process.env.TIKTOK_TEST_EVENT_CODE),
    data: [
      {
        event: normalizeText(input.event),
        event_id: buildEventId(input.eventId),
        event_time: typeof input.eventTime === 'number'
          ? Math.floor(input.eventTime)
          : Math.floor(Date.now() / 1000),
        page: {
          url: normalizeText(input.url),
          referrer: normalizeText(input.referrer),
        },
        user: {
          email: normalizedEmail ? hashValue(normalizedEmail) : undefined,
          external_id: hashValue(normalizedExternalId),
          ttp: normalizeText(input.ttp),
          ip: normalizeText(input.ip),
          user_agent: normalizeText(input.userAgent),
        },
        ad: {
          callback: normalizeText(input.ttclid),
        },
        properties: input.properties || undefined,
      },
    ],
  });

  const response = await fetch(TIKTOK_EVENT_TRACK_URL, {
    method: 'POST',
    headers: {
      'Access-Token': accessToken,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(payload),
  });

  const raw = await response.text();
  let data: any = null;
  try {
    data = raw ? JSON.parse(raw) : null;
  } catch {
    data = raw;
  }

  if (!response.ok) {
    throw new Error(`TikTok Events API request failed (${response.status})`);
  }

  if (data && typeof data === 'object' && 'code' in data && data.code !== 0) {
    throw new Error(`TikTok Events API returned code ${String(data.code)}`);
  }
}

export async function trackTikTokLeadSubmission(input: TikTokLeadEventInput): Promise<void> {
  await trackTikTokWebEvent({
    ...input,
    event: 'Lead',
    properties: {
      content_name: 'Rainmaker Sports lead',
      content_type: 'lead',
      description: normalizeText(input.description) || 'email_submit',
      status: normalizeText(input.status) || 'submitted',
    },
  });
}

export async function trackTikTokSubmitForm(input: TikTokLeadEventInput): Promise<void> {
  await trackTikTokWebEvent({
    ...input,
    event: 'SubmitForm',
    properties: {
      content_name: 'Rainmaker Sports form',
      content_type: 'lead',
      description: normalizeText(input.description) || 'form_submit',
      status: normalizeText(input.status) || 'submitted',
    },
  });
}

export async function trackTikTokLead(input: TikTokLeadEventInput): Promise<void> {
  await trackTikTokWebEvent({
    ...input,
    event: 'CompleteRegistration',
    properties: {
      content_name: 'Rainmaker Sports account',
      content_type: 'lead',
      description: normalizeText(input.description) || 'signup',
      status: normalizeText(input.status) || 'completed',
    },
  });
}
