/* ============================================================
 * Copyright (c) 2026 RAVAPI Soluções. www.ravapi.com
 * Fase 5 — logo da empresa (docs/decisoes.md §16, pendência #3)
 *
 * O byte-a-byte vai pro bucket; só o resultado (hash, chave, mime,
 * tamanho) entra no banco. `bytes_sha256` é o que confere que o logo
 * gravado é o mesmo que a empresa mandou, sem precisar baixar o arquivo
 * de novo — o mesmo raciocínio de db/migrations/006 para a leitura
 * pública, aplicado à escrita.
 * ============================================================ */

import { createHash } from 'node:crypto';
import { emTransacao, type Pool } from '../db/client.ts';
import { exigir, type UsuarioRef } from '../core/identity.ts';
import { NaoEncontrado } from '../core/errors.ts';
import { validarLogo, extensaoPara } from '../core/assets.ts';
import type { StorageAdapter } from './storage.ts';

export class AssetsService {
  constructor(
    private readonly pool: Pool,
    private readonly storage: StorageAdapter,
  ) {}

  async salvarLogo(u: UsuarioRef, companyId: string, bytes: Buffer, mime: string) {
    exigir(u, 'gerir_cadastros');
    validarLogo(mime, bytes.length);

    const sha256 = createHash('sha256').update(bytes).digest('hex');
    const chave = `logos/${companyId}/${sha256}.${extensaoPara(mime)}`;

    return emTransacao(this.pool, async (x) => {
      const { rows: empresa } = await x.query(
        'SELECT id FROM recibos.companies WHERE id = $1', [companyId],
      );
      if (!empresa[0]) throw new NaoEncontrado('Empresa');

      // Sobe pro bucket dentro da transação, de propósito: se o INSERT ou
      // o UPDATE falhar depois, o rollback não desfaz o upload — mas a
      // chave é o hash do conteúdo, então subir de novo é idempotente.
      // O que não pode acontecer é o banco apontar pra uma chave que
      // nunca chegou a existir no bucket.
      await this.storage.salvar(chave, bytes, mime);

      const { rows } = await x.query(
        `INSERT INTO recibos.assets (tenant_id, tipo, mime, bytes_sha256, tamanho, storage_key)
         VALUES (current_setting('app.tenant_id')::uuid, 'logo', $1, $2, $3, $4)
         RETURNING *`,
        [mime, sha256, bytes.length, chave],
      );
      const asset = rows[0];

      await x.query(
        'UPDATE recibos.companies SET logo_asset_id = $1, atualizado_em = now() WHERE id = $2',
        [asset.id, companyId],
      );

      return asset;
    });
  }
}
