import { sql } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client.js';

export type ShareChannel =
  | 'whatsapp'
  | 'instagram'
  | 'facebook'
  | 'twitter'
  | 'telegram'
  | 'copy'
  | 'email'
  | 'sms'
  | 'other'
  | 'direct';

export type GenerateShareLinkInput = {
  targetUrl: string;
  channel: ShareChannel;
  dealId?: string;
  ownerUserId?: string;
  campaignName?: string;
  dealSlug?: string;
};

export type GenerateShareLinkResult = {
  slug: string;
  shortUrl: string;
  utmUrl: string;
};

export type ShareLinkRow = {
  id: string;
  slug: string;
  targetUrl: string;
  utmSource: string;
  utmMedium: string;
  utmCampaign: string;
  channel: ShareChannel;
  isActive: boolean;
  expiresAt: Date | null;
};

const BASE62 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

function generateSlug(): string {
  const bytes = new Uint8Array(8);
  crypto.getRandomValues(bytes);
  return Array.from(bytes)
    .map((b) => BASE62[b % 62])
    .join('');
}

/**
 * Mint or return an existing share link.
 *
 * Idempotency window: if the same (dealId, channel, ownerUserId) was created
 * within the last 24h and is still active, return the existing row.
 * Uses IS NOT DISTINCT FROM for nullable columns (NULL = NULL in this context).
 */
export async function generateShareLink(
  db: DrizzleClient,
  env: { SHARE_BASE_URL?: string; PUBLIC_SITE_URL: string },
  input: GenerateShareLinkInput,
): Promise<GenerateShareLinkResult> {
  const shareBaseUrl = env.SHARE_BASE_URL ?? 'https://multi.deal';

  // Idempotency check.
  const existing = (await db.execute<{ id: string; slug: string }>(sql`
    SELECT id, slug FROM share_links
    WHERE deal_id IS NOT DISTINCT FROM ${input.dealId ?? null}
      AND target_url = ${input.targetUrl}
      AND channel = ${input.channel}
      AND owner_user_id IS NOT DISTINCT FROM ${input.ownerUserId ?? null}
      AND created_at > NOW() - INTERVAL '24 hours'
      AND is_active = TRUE
    LIMIT 1
  `)) as { rows: Array<{ id: string; slug: string }> };

  if (existing.rows.length > 0) {
    const row = existing.rows[0]!;
    const shortUrl = `${shareBaseUrl}/s/${row.slug}`;
    const utmUrl = buildUtmUrl(
      input.targetUrl,
      input.channel,
      row.slug,
      input.dealSlug,
      input.campaignName,
    );
    return { slug: row.slug, shortUrl, utmUrl };
  }

  // Mint a new slug — retry once on unique conflict.
  for (let attempt = 0; attempt < 2; attempt++) {
    const slug = generateSlug();
    try {
      const inserted = (await db.execute<{ id: string; slug: string }>(sql`
        INSERT INTO share_links
          (slug, target_url, deal_id, owner_user_id, channel, campaign_name,
           utm_source, utm_medium, utm_campaign)
        VALUES
          (${slug}, ${input.targetUrl}, ${input.dealId ?? null}, ${input.ownerUserId ?? null},
           ${input.channel}, ${input.campaignName ?? null},
           ${input.channel}, 'social',
           ${input.dealSlug ?? input.campaignName ?? 'direct'})
        RETURNING id, slug
      `)) as { rows: Array<{ id: string; slug: string }> };

      const row = inserted.rows[0];
      if (row) {
        const shortUrl = `${shareBaseUrl}/s/${row.slug}`;
        const utmUrl = buildUtmUrl(
          input.targetUrl,
          input.channel,
          row.slug,
          input.dealSlug,
          input.campaignName,
        );
        return { slug: row.slug, shortUrl, utmUrl };
      }
    } catch (err: unknown) {
      if (attempt === 1) throw err;
      // Unique constraint on slug — retry with a new slug.
    }
  }

  throw new Error('Failed to generate share link after 2 attempts');
}

/**
 * Look up a share link by slug for the redirect handler.
 * Returns null if not found.
 */
export async function lookupShareLink(
  db: DrizzleClient,
  slug: string,
): Promise<ShareLinkRow | null> {
  type ShareLinkDbRow = {
    id: string;
    slug: string;
    target_url: string;
    utm_source: string;
    utm_medium: string;
    utm_campaign: string;
    channel: string;
    is_active: boolean;
    expires_at: string | null;
  };

  const result = (await db.execute<ShareLinkDbRow>(sql`
    SELECT id, slug, target_url, utm_source, utm_medium, utm_campaign,
           channel, is_active, expires_at
    FROM share_links
    WHERE slug = ${slug}
    LIMIT 1
  `)) as { rows: ShareLinkDbRow[] };

  if (!result.rows.length) return null;
  const r = result.rows[0]!;
  return {
    id: r.id,
    slug: r.slug,
    targetUrl: r.target_url,
    utmSource: r.utm_source,
    utmMedium: r.utm_medium,
    utmCampaign: r.utm_campaign,
    channel: r.channel as ShareChannel,
    isActive: r.is_active,
    expiresAt: r.expires_at ? new Date(r.expires_at) : null,
  };
}

function buildUtmUrl(
  targetUrl: string,
  channel: string,
  slug: string,
  dealSlug?: string,
  campaignName?: string,
): string {
  const url = new URL(targetUrl);
  url.searchParams.set('utm_source', channel);
  url.searchParams.set('utm_medium', 'social');
  url.searchParams.set('utm_campaign', dealSlug ?? campaignName ?? 'direct');
  url.searchParams.set('utm_content', slug);
  return url.toString();
}
