// GET  /api/me/notification-subscriptions -> { eventKeys, channelTypes, matrix }
// PUT  /api/me/notification-subscriptions -> body { event_key, channel_type, enabled } -> { subscription }
//
// SUB-04. Authentication: requireAuth(). Write target is always session.user.id.
// T-09-02-01: no user_id accepted from body or query.
// T-09-02-03: event_key length-bounded; channel_type via isPersonalChannelType;
//             enabled typeof === 'boolean'.
//
// GET matrix shape: { event_key → { channel_type → boolean } }
// Default: true when no row exists in user_event_subscriptions (D-15 opt-out model).

import { NextRequest, NextResponse } from 'next/server';
import { requireAuth } from '@/lib/auth-utils';
import { postgresClient } from '@/lib/services/postgres-client';
import { NotifyEventKey, UserEventSubscription } from '@/lib/types/pipeline';
import { isPersonalChannelType } from '@/lib/services/personal-channels';

export async function GET(): Promise<NextResponse> {
  const { session, error } = await requireAuth();
  if (error) return error;

  try {
    // Query A: all active event keys ordered by sort_order
    const eventKeysResult = await postgresClient.query<NotifyEventKey>(
      `SELECT key, display_label, description, sort_order
       FROM notify_event_keys
       WHERE is_active = true
       ORDER BY sort_order ASC, key ASC`,
      [],
    );

    // Query B: channel types configured for this user
    const channelTypesResult = await postgresClient.query<{ channel_type: string }>(
      `SELECT channel_type
       FROM notification_channels
       WHERE owner_user_id = $1 AND is_active = true
       ORDER BY channel_type ASC`,
      [session!.user.id],
    );

    // Query C: stored subscription rows for this user
    const subscriptionsResult = await postgresClient.query<UserEventSubscription>(
      `SELECT event_key, channel_type, enabled
       FROM user_event_subscriptions
       WHERE user_id = $1`,
      [session!.user.id],
    );

    const channelTypes = channelTypesResult.rows.map((r) => r.channel_type);

    // Build stored subscription lookup for O(1) access
    const storedMap = new Map<string, boolean>();
    for (const row of subscriptionsResult.rows) {
      storedMap.set(`${row.event_key}:${row.channel_type}`, row.enabled);
    }

    // Build matrix: event_key → channel_type → boolean.
    // Default is true (D-15 / T-09-02-03: row absence means enabled).
    const matrix: Record<string, Record<string, boolean>> = {};
    for (const ek of eventKeysResult.rows) {
      matrix[ek.key] = {};
      for (const ct of channelTypes) {
        const stored = storedMap.get(`${ek.key}:${ct}`);
        matrix[ek.key][ct] = stored !== undefined ? stored : true;
      }
    }

    // camelCase transform for event keys
    const eventKeys = eventKeysResult.rows.map((r) => ({
      key: r.key,
      displayLabel: r.display_label,
      description: r.description,
      sortOrder: r.sort_order,
    }));

    return NextResponse.json({ eventKeys, channelTypes, matrix });
  } catch (e) {
    console.error('GET /api/me/notification-subscriptions failed:', e);
    return NextResponse.json(
      { error: 'Failed to read subscriptions', message: e instanceof Error ? e.message : 'unknown' },
      { status: 500 },
    );
  }
}

export async function PUT(request: NextRequest): Promise<NextResponse> {
  const { session, error } = await requireAuth();
  if (error) return error;

  let body: unknown;
  try {
    body = await request.json();
  } catch {
    return NextResponse.json(
      { error: 'Invalid JSON', message: 'Request body must be JSON' },
      { status: 400 },
    );
  }

  if (!body || typeof body !== 'object') {
    return NextResponse.json(
      { error: 'Invalid body', message: 'Request body must be a JSON object' },
      { status: 400 },
    );
  }

  const { event_key, channel_type, enabled } = body as Record<string, unknown>;

  // Validate event_key: non-empty string ≤ 128 chars
  if (typeof event_key !== 'string' || event_key.length === 0 || event_key.length > 128) {
    return NextResponse.json(
      { error: 'Invalid event_key', message: 'event_key must be a non-empty string of at most 128 characters' },
      { status: 400 },
    );
  }

  // Validate channel_type via isPersonalChannelType allowlist
  if (!isPersonalChannelType(channel_type)) {
    return NextResponse.json(
      { error: 'Invalid channel_type', message: 'channel_type must be one of: teams, ntfy' },
      { status: 400 },
    );
  }

  // Validate enabled: must be a boolean
  if (typeof enabled !== 'boolean') {
    return NextResponse.json(
      { error: 'Invalid enabled', message: 'enabled must be a boolean' },
      { status: 400 },
    );
  }

  try {
    // Composite PK UPSERT — write target is always session.user.id (T-09-02-01).
    const result = await postgresClient.query<UserEventSubscription>(
      `INSERT INTO user_event_subscriptions (user_id, event_key, channel_type, enabled, updated_at)
       VALUES ($1, $2, $3, $4, NOW())
       ON CONFLICT (user_id, event_key, channel_type) DO UPDATE
         SET enabled = EXCLUDED.enabled, updated_at = NOW()
       RETURNING user_id, event_key, channel_type, enabled, updated_at`,
      [session!.user.id, event_key, channel_type, enabled],
    );

    const row = result.rows[0];
    return NextResponse.json({
      subscription: {
        eventKey: row.event_key,
        channelType: row.channel_type,
        enabled: row.enabled,
      },
    });
  } catch (e) {
    console.error('PUT /api/me/notification-subscriptions failed:', e);
    return NextResponse.json(
      { error: 'Failed to update subscription', message: e instanceof Error ? e.message : 'unknown' },
      { status: 500 },
    );
  }
}
