import { BadRequestException, Body, Controller, Headers, Post } from '@nestjs/common';
import { IiosTemplateChannel } from '@prisma/client';
import { SessionVerifier } from '../platform/session.verifier';
import { ActorResolver, type MessagePrincipal } from '../identity/actor.resolver';
import { TemplatedSender, type ExternalChannel } from './templated-sender';
import { TemplateService } from './template.service';
import { PreviewTemplateDto, SendTemplateDto } from './template.dto';
import type { TemplateSource } from './template.model';

@Controller('v1/templates')
export class TemplateController {
  constructor(
    private readonly sender: TemplatedSender,
    private readonly templates: TemplateService,
    private readonly session: SessionVerifier,
    private readonly actors: ActorResolver,
  ) {}

  /** Render a stored/inline template and queue it for external delivery (EMAIL/SMS). */
  @Post('send')
  async send(@Body() body: SendTemplateDto, @Headers('authorization') authorization?: string) {
    const principal = this.principal(authorization);
    const scope = await this.actors.resolveScope(principal);
    return this.sender.sendTemplated({
      source: this.source(body),
      channel: body.channel as ExternalChannel,
      target: body.target,
      vars: body.vars ?? {},
      scopeId: scope.id,
      ...(body.locale ? { locale: body.locale } : {}),
      idempotencyKey: body.idempotencyKey,
      ...(body.purpose ? { purpose: body.purpose } : {}),
    });
  }

  /** Render only — no send. For marketing/QA to eyeball copy before it goes out. */
  @Post('preview')
  async preview(@Body() body: PreviewTemplateDto, @Headers('authorization') authorization?: string) {
    const principal = this.principal(authorization);
    const scope = await this.actors.resolveScope(principal);
    const { content } = await this.templates.render(this.source(body), body.vars ?? {}, {
      channel: body.channel as IiosTemplateChannel,
      ...(body.locale ? { locale: body.locale } : {}),
      scopeId: scope.id,
    });
    return content;
  }

  /** Map the DTO's key|inline into a TemplateSource (exactly one must be present). */
  private source(body: { key?: string; version?: number; inline?: { subject?: string; html?: string; text?: string; variables?: string[] } }): TemplateSource {
    if (body.inline && body.key) throw new BadRequestException('provide either "key" or "inline", not both');
    if (body.inline) return { inline: body.inline };
    if (body.key) return body.version != null ? { key: body.key, version: body.version } : { key: body.key };
    throw new BadRequestException('one of "key" or "inline" is required');
  }

  private principal(authorization?: string): MessagePrincipal {
    const token = (authorization ?? '').replace(/^Bearer\s+/i, '');
    if (!token) throw new BadRequestException('Authorization bearer token is required');
    return this.session.verify(token);
  }
}
