import { Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common';
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
import { PrismaService } from 'src/prisma/prisma.service';
import { envs } from 'src/config';
import { UpsertMarangatuConfigDto } from './dto/upsert-marangatu-config.dto';
import { MarangatuGateway } from './marangatu.gateway';

const ALGORITHM = 'aes-256-cbc';
const IV_LENGTH = 16;

function getEncryptionKey(): Buffer {
  const raw = envs.aiEncryptionKey ?? '';
  if (raw.length !== 32) {
    throw new InternalServerErrorException('MARANGATU_ENCRYPTION_KEY debe tener exactamente 32 caracteres');
  }
  return Buffer.from(raw, 'utf8');
}

function encrypt(text: string): string {
  const key = getEncryptionKey();
  const iv = randomBytes(IV_LENGTH);
  const cipher = createCipheriv(ALGORITHM, key, iv);
  const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
  return `${iv.toString('hex')}:${encrypted.toString('hex')}`;
}

function decrypt(encrypted: string): string {
  const key = getEncryptionKey();
  const [ivHex, dataHex] = encrypted.split(':');
  const iv = Buffer.from(ivHex, 'hex');
  const data = Buffer.from(dataHex, 'hex');
  const decipher = createDecipheriv(ALGORITHM, key, iv);
  const decrypted = Buffer.concat([decipher.update(data), decipher.final()]);
  return decrypted.toString('utf8');
}

@Injectable()
export class MarangatuConfigService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly gateway: MarangatuGateway,
  ) {}

  async upsertConfig(empresaId: string, dto: UpsertMarangatuConfigDto) {
    const existing = await this.prisma.marangatu_empresa_config.findUnique({
      where: { empresa_id: empresaId },
    });

    let passwordEncrypted = existing?.password_encrypted ?? null;
    if (dto.password) {
      passwordEncrypted = encrypt(dto.password);
    }
    if (!passwordEncrypted) {
      throw new InternalServerErrorException('Se requiere una contraseña');
    }

    const data = {
      username: dto.username,
      password_encrypted: passwordEncrypted,
      activo_compras: dto.activo_compras ?? existing?.activo_compras ?? false,
      activo_ventas: dto.activo_ventas ?? existing?.activo_ventas ?? false,
      updated_at: new Date(),
    };

    const cfg = await this.prisma.marangatu_empresa_config.upsert({
      where: { empresa_id: empresaId },
      create: { empresa_id: empresaId, ...data },
      update: data,
    });

    if (!existing) {
      this.gateway.activateWs();
    }

    const { password_encrypted, ...rest } = cfg;
    return { ...rest, tiene_password: !!password_encrypted };
  }

  async getConfig(empresaId: string) {
    const cfg = await this.prisma.marangatu_empresa_config.findUnique({
      where: { empresa_id: empresaId },
    });
    if (!cfg) return null;
    const { password_encrypted, ...rest } = cfg;
    return { ...rest, tiene_password: !!password_encrypted };
  }

  async getPassword(empresaId: string): Promise<string> {
    const cfg = await this.prisma.marangatu_empresa_config.findUnique({
      where: { empresa_id: empresaId },
    });
    if (!cfg?.password_encrypted) {
      throw new NotFoundException('Configuración Marangatu no encontrada');
    }
    return decrypt(cfg.password_encrypted);
  }

  async getFullConfig(empresaId: string) {
    const cfg = await this.prisma.marangatu_empresa_config.findUnique({
      where: { empresa_id: empresaId },
    });
    if (!cfg) throw new NotFoundException('Configuración Marangatu no encontrada');
    return cfg;
  }

  async updateSyncTimestamp(empresaId: string, tipo: 'compras' | 'ventas') {
    const field = tipo === 'compras' ? 'ultima_sync_compras' : 'ultima_sync_ventas';
    await this.prisma.marangatu_empresa_config.update({
      where: { empresa_id: empresaId },
      data: { [field]: new Date(), updated_at: new Date() },
    });
  }
}
