import { Injectable } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model } from 'mongoose'
import { AuditService, type AuditActor } from '../audit/audit.service.js'
import { TenantBranding, type TenantBrandingDocument } from '../schemas/tenant-branding.schema.js'
import { Tenant, type TenantDocument } from '../schemas/tenant.schema.js'
import type { UpdateTenantBrandingDto } from './dto/update-tenant-branding.dto.js'

export interface TenantBrandingView {
  name: string
  brandColor?: string
  primaryDomain?: string
  emailTemplates: Array<{ key: string; subject: string; body: string }>
}

// Customer whitelabel branding. Name + brandColor are read/written on the
// Tenant doc (source of truth); email-template overrides live in the
// TenantBranding doc. The portal page reads the combined view and saves the
// whole thing back in one PUT (same full-replace shape as partner branding).
@Injectable()
export class TenantBrandingService {
  constructor(
    @InjectModel(Tenant.name) private readonly tenantModel: Model<TenantDocument>,
    @InjectModel(TenantBranding.name) private readonly brandingModel: Model<TenantBrandingDocument>,
    private readonly audit: AuditService,
  ) {}

  async get(tenant: TenantDocument): Promise<TenantBrandingView> {
    const branding = await this.brandingModel.findOne({ tenantId: tenant._id }).exec()
    return {
      name: tenant.name,
      brandColor: tenant.brandColor,
      primaryDomain: tenant.domains?.[0],
      emailTemplates: (branding?.emailTemplates ?? []).map((t) => ({
        key: t.key,
        subject: t.subject,
        body: t.body,
      })),
    }
  }

  async put(
    tenant: TenantDocument,
    dto: UpdateTenantBrandingDto,
    actor?: AuditActor,
  ): Promise<TenantBrandingView> {
    // Name + accent live on the Tenant doc.
    const set: Record<string, unknown> = {}
    if (dto.name !== undefined) set.name = dto.name
    if (dto.brandColor !== undefined) set.brandColor = dto.brandColor
    if (Object.keys(set).length) {
      await this.tenantModel.updateOne({ _id: tenant._id }, { $set: set }).exec()
    }

    // Email-template overrides are a full replace (the page edits the whole set).
    if (dto.emailTemplates !== undefined) {
      await this.brandingModel
        .findOneAndUpdate(
          { tenantId: tenant._id },
          { $set: { emailTemplates: dto.emailTemplates } },
          { upsert: true, new: true, runValidators: true, setDefaultsOnInsert: true },
        )
        .exec()
    }

    void this.audit.record(
      {
        action: 'tenant.branding_updated',
        resourceType: 'tenant',
        resourceId: String(tenant._id),
        resourceName: dto.name ?? tenant.name,
        tenantSlug: tenant.slug,
        metadata: {
          fields: Object.keys(set),
          templates: dto.emailTemplates?.length ?? 0,
        },
      },
      actor,
    )

    const fresh = await this.tenantModel.findById(tenant._id).exec()
    return this.get(fresh ?? tenant)
  }
}
