import { HttpError, type RequestContext } from '../../core/http.js';
import { intParam, stringParam } from '../../core/request.js';
import { query } from '../../core/db.js';
import { normalizeNotificationStatus } from '../notifications/service.js';
import { requireTenantAdmin, requireTenantPermission } from './auth.js';

const NOTIFICATION_TYPES = [
  'feedback_status_updated',
  'feedback_reward_granted',
  'badge_granted',
  'point_exchange_completed',
  'point_exchange_pending_fulfillment',
];

function optionalUuidString(value: unknown, key: string) {
  const candidate = typeof value === 'string' && value.trim() ? value.trim() : null;
  if (!candidate) return null;
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(candidate)) {
    throw new HttpError(400, `${key} must be a UUID`, 'INVALID_UUID');
  }
  return candidate;
}

function notificationTypeParam(ctx: RequestContext) {
  const notificationType = stringParam(ctx, 'notificationType') || stringParam(ctx, 'type');
  if (!notificationType) return '';
  if (!NOTIFICATION_TYPES.includes(notificationType)) {
    throw new HttpError(400, `Invalid notificationType: ${notificationType}`, 'INVALID_NOTIFICATION_TYPE');
  }
  return notificationType;
}

export async function tenantUserNotificationsRoute(ctx: RequestContext) {
  const auth = await requireTenantAdmin(ctx);
  requireTenantPermission(auth, 'notifications:read');
  const limit = intParam(ctx, 'limit', 100, 500);
  const userId = optionalUuidString(stringParam(ctx, 'userId'), 'userId');
  const status = stringParam(ctx, 'status');
  const notificationType = notificationTypeParam(ctx);
  const params: unknown[] = [auth.tenantId];
  const filters = ['n.tenant_id = $1'];

  if (userId) {
    params.push(userId);
    filters.push(`n.user_id = $${params.length}::uuid`);
  }
  if (status) {
    normalizeNotificationStatus(status);
    params.push(status);
    filters.push(`n.status = $${params.length}`);
  }
  if (notificationType) {
    params.push(notificationType);
    filters.push(`n.notification_type = $${params.length}`);
  }
  params.push(limit);

  const items = await query(
    `
    select n.id, n.user_id as "userId", u.name as "userName",
           u.phone as "userPhone", null::text as "userAvatarUrl",
           n.notification_type as "notificationType", n.status, n.severity,
           n.title, n.message, n.action_label as "actionLabel",
           n.action_path as "actionPath", n.source_type as "sourceType",
           n.source_id as "sourceId", n.metadata, n.created_by as "createdBy",
           creator.name as "createdByName", n.read_at as "readAt",
           n.created_at as "createdAt", n.updated_at as "updatedAt"
    from public.user_notifications n
    join public.platform_users u on u.id = n.user_id
    left join public.platform_users creator on creator.id = n.created_by
    where ${filters.join(' and ')}
    order by n.created_at desc
    limit $${params.length}
    `,
    params,
  );

  const summaryRows = await query<{ status: string; count: number }>(
    `
    select status, count(*)::int as count
    from public.user_notifications
    where tenant_id = $1
    group by status
    `,
    [auth.tenantId],
  );

  return {
    items,
    summary: Object.fromEntries(summaryRows.map(item => [item.status, Number(item.count || 0)])),
  };
}
