// Cross-channel entitlement query API.
//
// Endpoints:
//   GET  /api/entitlements/check     ?customer_did=&product_id=[&livemode=]
//   GET  /api/entitlements/list      ?customer_did=[&livemode=]
//
// Auth model:
//   - Component-to-component calls (other blocklets via @blocklet/payment-client):
//     trusted via the component signature; `roles: ['owner','admin']` is the gate.
//   - Logged-in end users (mobile demo, web SPA): `mine: true` lets them in iff
//     their DID matches the query's customer_did — enforced in the handler.

import { Router } from 'express';
import Joi from 'joi';

import { checkEntitlement, listEntitlements } from '../libs/entitlement';
import logger from '../libs/logger';
import { authenticate } from '../libs/security';
import { PaymentMethod } from '../store/models';

const router = Router();
// component+owner/admin for cross-blocklet calls; ensureLogin for end users —
// handler then enforces that non-admin users can only query their own DID.
const auth = authenticate<PaymentMethod>({ component: true, roles: ['owner', 'admin'], ensureLogin: true });

function isAdminUser(role?: string): boolean {
  return role === 'owner' || role === 'admin';
}

// Strip the `did:abt:` prefix if present so callers can compare DIDs across
// the two shapes that show up in the codebase (bare base58 vs canonical).
// The CF Workers AUTH_SERVICE returns bare addresses; clients send canonical.
function canonicalDid(did: string | undefined | null): string {
  if (!did) return '';
  return did.startsWith('did:abt:') ? did.slice('did:abt:'.length) : did;
}

function isSelf(req: any, customerDid: string): boolean {
  const a = canonicalDid(req.user?.did);
  const b = canonicalDid(customerDid);
  return !!a && a === b;
}

const checkQuerySchema = Joi.object<{
  customer_did: string;
  product_id: string;
  livemode?: string | boolean;
}>({
  customer_did: Joi.string().required(),
  product_id: Joi.string().required(),
  livemode: Joi.alternatives(Joi.boolean(), Joi.string().valid('true', 'false')),
});

const listQuerySchema = Joi.object<{
  customer_did: string;
  livemode?: string | boolean;
}>({
  customer_did: Joi.string().required(),
  livemode: Joi.alternatives(Joi.boolean(), Joi.string().valid('true', 'false')),
});

function parseLivemode(value: string | boolean | undefined, fallback: boolean): boolean {
  if (typeof value === 'boolean') return value;
  if (value === 'true') return true;
  if (value === 'false') return false;
  return fallback;
}

router.get('/check', auth, async (req, res) => {
  try {
    const input = await checkQuerySchema.validateAsync(req.query, { stripUnknown: true });
    if (!isAdminUser((req as any).user?.role) && !isSelf(req, input.customer_did)) {
      res.status(403).json({ error: 'Cannot query entitlements for other customers' });
      return;
    }
    const livemode = parseLivemode(input.livemode, !!req.livemode);
    const result = await checkEntitlement({
      customer_did: input.customer_did,
      product_id: input.product_id,
      livemode,
    });
    res.json(result);
  } catch (err: any) {
    logger.error('entitlements/check failed', { error: err?.message, stack: err?.stack });
    res.status(400).json({ error: err?.message ?? 'check failed' });
  }
});

router.get('/list', auth, async (req, res) => {
  try {
    const input = await listQuerySchema.validateAsync(req.query, { stripUnknown: true });
    if (!isAdminUser((req as any).user?.role) && !isSelf(req, input.customer_did)) {
      res.status(403).json({ error: 'Cannot list entitlements for other customers' });
      return;
    }
    const livemode = parseLivemode(input.livemode, !!req.livemode);
    const list = await listEntitlements({ customer_did: input.customer_did, livemode });
    res.json({ list });
  } catch (err: any) {
    logger.error('entitlements/list failed', { error: err?.message, stack: err?.stack });
    res.status(400).json({ error: err?.message ?? 'list failed' });
  }
});

export default router;
