import { NextResponse } from 'next/server';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { errorResponse } from '@/lib/errors';
import { entriesForSections, registryFor } from '@/lib/settings/registry';
import { resolveForAdminAPI } from '@/lib/settings/resolver';

/**
 * GET /api/v1/admin/settings/resolved?sections=documenso.api,documenso.signers
 * GET /api/v1/admin/settings/resolved?keys=branding_logo_url,smtp_host_override
 *
 * Returns the resolved value + source (port/global/env/default) for every
 * requested registry entry. Drives both the registry-driven admin form
 * (sections param) and the onboarding-checklist auto-detection (keys
 * param) - both need port→global→env→default resolution rather than the
 * raw `/admin/settings` rows (which only show DB writes).
 *
 * Either parameter is supported; if both are present the sets union.
 * Sensitive fields surface `isSet` only - never the decrypted value.
 */
export const GET = withAuth(
  withPermission('admin', 'manage_settings', async (req, ctx) => {
    try {
      const url = new URL(req.url);
      const sectionsParam = url.searchParams.get('sections');
      const keysParam = url.searchParams.get('keys');
      if (!sectionsParam && !keysParam) {
        return NextResponse.json({ data: { entries: [], values: {} } }, { status: 200 });
      }
      const sections = sectionsParam
        ? sectionsParam
            .split(',')
            .map((s) => s.trim())
            .filter(Boolean)
        : [];
      const extraKeys = keysParam
        ? keysParam
            .split(',')
            .map((s) => s.trim())
            .filter(Boolean)
        : [];
      const sectionEntries = entriesForSections(sections);
      const keyEntries = extraKeys
        .map((k) => registryFor(k))
        .filter((e): e is NonNullable<typeof e> => Boolean(e));
      // Dedupe by `key` so section + key overlap doesn't double-resolve.
      const seen = new Set<string>();
      const entries = [...sectionEntries, ...keyEntries].filter((e) => {
        if (seen.has(e.key)) return false;
        seen.add(e.key);
        return true;
      });
      const keys = entries.map((e) => e.key);
      const resolved = await resolveForAdminAPI(keys, ctx.portId);

      // Return the entry metadata so the client can render labels/types
      // without bundling the registry into the client JS. Strip the
      // `validator` + `transform` function references - they're not
      // JSON-serializable.
      const entriesForClient = entries.map((e) => ({
        key: e.key,
        section: e.section,
        label: e.label,
        description: e.description,
        type: e.type,
        options: e.options,
        encrypted: !!e.encrypted,
        sensitive: !!(e.sensitive || e.encrypted),
        scope: e.scope,
        envFallback: e.envFallback,
        placeholder: e.placeholder,
        defaultValue: e.defaultValue,
      }));

      const values: Record<string, unknown> = {};
      for (const [k, r] of resolved.entries()) {
        values[k] = r;
      }

      return NextResponse.json({ data: { entries: entriesForClient, values } });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);
