import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

// Minimal Web Push implementation using Deno crypto
// Copied verbatim from push-notify/index.ts
async function sendWebPush(
  subscription: { endpoint: string; keys: { p256dh: string; auth: string } },
  payload: string,
  vapidPrivateKeyB64: string,
  vapidPublicKeyB64: string,
): Promise<number> {
  const endpoint = subscription.endpoint;
  const audience = new URL(endpoint).origin;

  const header = { alg: 'ES256', typ: 'JWT' };
  const now = Math.floor(Date.now() / 1000);
  const claims = {
    aud: audience,
    exp: now + 12 * 3600,
    sub: 'mailto:admin@oskolkam.net',
  };

  const encode = (obj: object) =>
    btoa(JSON.stringify(obj))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');

  const headerB64 = encode(header);
  const claimsB64 = encode(claims);
  const signingInput = `${headerB64}.${claimsB64}`;

  // Import private key from raw 32-byte scalar
  const privKeyBytes = Uint8Array.from(
    atob(vapidPrivateKeyB64.replace(/-/g, '+').replace(/_/g, '/')),
    (c) => c.charCodeAt(0),
  );
  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    privKeyBytes,
    { name: 'ECDSA', namedCurve: 'P-256' },
    false,
    ['sign'],
  );

  const encoder = new TextEncoder();
  const sig = await crypto.subtle.sign(
    { name: 'ECDSA', hash: 'SHA-256' },
    cryptoKey,
    encoder.encode(signingInput),
  );
  const sigB64 = btoa(String.fromCharCode(...new Uint8Array(sig)))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
  const jwt = `${signingInput}.${sigB64}`;

  const res = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Authorization': `vapid t=${jwt},k=${vapidPublicKeyB64}`,
      'Content-Type': 'application/octet-stream',
      'TTL': '86400',
    },
    body: encoder.encode(payload),
  });
  return res.status;
}

const supabaseAdmin = createClient(
  Deno.env.get('SUPABASE_URL')!,
  Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,
);

Deno.serve(async () => {
  const now = new Date();
  const from = new Date(now.getTime() + 50 * 60 * 1000).toISOString();
  const to = new Date(now.getTime() + 70 * 60 * 1000).toISOString();

  const { data: orders } = await supabaseAdmin
    .from('orders')
    .select('id, name, scheduled_at, address, film_thickness, area_sqm')
    .gte('scheduled_at', from)
    .lte('scheduled_at', to)
    .neq('status', 'закрыт')
    .is('reminder_sent_at', null);

  if (!orders?.length) return new Response('no reminders', { status: 200 });

  const { data: subs } = await supabaseAdmin.from('push_subscriptions').select('subscription');
  if (!subs?.length) return new Response('no subscribers', { status: 200 });

  const vapidPriv = Deno.env.get('VAPID_PRIVATE_KEY')!;
  const vapidPub = Deno.env.get('VITE_VAPID_PUBLIC_KEY')!;

  for (const order of orders) {
    const time = new Date(order.scheduled_at).toLocaleTimeString('ru-RU', {
      hour: '2-digit',
      minute: '2-digit',
    });
    const body = `${order.name} — ${time}${order.address ? `, ${order.address}` : ''}`;
    const payload = JSON.stringify({ title: 'Визит через 1 час', body, url: '/admin/kanban' });

    for (const { subscription: sub } of subs) {
      try {
        const status = await sendWebPush(sub, payload, vapidPriv, vapidPub);
        // Clean up expired/invalid subscriptions
        if (status === 404 || status === 410) {
          await supabaseAdmin
            .from('push_subscriptions')
            .delete()
            .eq('subscription->>endpoint', sub.endpoint);
        }
      } catch (_) {
        // Ignore individual push failures — don't abort the whole batch
      }
    }

    // Mark reminder as sent to prevent duplicates
    await supabaseAdmin
      .from('orders')
      .update({ reminder_sent_at: new Date().toISOString() })
      .eq('id', order.id);
  }

  return new Response(`reminders sent: ${orders.length}`, { status: 200 });
});
