import { DeleteObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { ecommerce_novedad_tipo } from '@prisma/client';
import { IsBoolean, IsEnum, IsInt, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator';
import sharp from 'sharp';
import { envs } from 'src/config';
import { PrismaService } from 'src/prisma/prisma.service';

export class UpsertNovedadDto {
  @IsOptional()
  @IsEnum(ecommerce_novedad_tipo)
  tipo?: ecommerce_novedad_tipo;

  @IsOptional()
  @IsString()
  @MaxLength(200)
  titulo?: string;

  @IsOptional()
  @IsString()
  descripcion?: string;

  @IsOptional()
  @IsString()
  @MaxLength(60)
  tag?: string;

  @IsOptional()
  @IsString()
  @MaxLength(80)
  cta_label?: string;

  @IsOptional()
  @IsString()
  @MaxLength(120)
  target_category?: string;

  @IsOptional()
  @IsString()
  @MaxLength(500)
  imagen_url?: string;

  @IsOptional()
  @IsInt()
  @Min(0)
  @Max(100)
  prioridad?: number;

  @IsOptional()
  @IsBoolean()
  activo?: boolean;
}

@Injectable()
export class EcommerceNovedadesService {
  private readonly s3: S3Client;

  constructor(private readonly prisma: PrismaService) {
    this.s3 = new S3Client({
      region: envs.doSpacesRegion,
      endpoint: envs.doSpacesEndpoint || undefined,
      credentials:
        envs.doSpacesKey && envs.doSpacesSecret
          ? { accessKeyId: envs.doSpacesKey, secretAccessKey: envs.doSpacesSecret }
          : undefined,
      forcePathStyle: false,
    });
  }

  private get bucket(): string {
    if (!envs.doSpacesBucket) throw new Error('DO_SPACES_BUCKET no configurado');
    return envs.doSpacesBucket;
  }

  private get publicBase(): string {
    return (envs.doSpacesPublicUrl ?? '').replace(/\/+$/, '');
  }

  async list(empresaId: string) {
    const rows = await this.prisma.ecommerce_novedades.findMany({
      where: { empresa_id: empresaId },
      orderBy: [{ prioridad: 'desc' }, { created_at: 'asc' }],
    });
    return rows.map(this.serialize);
  }

  async create(empresaId: string, dto: UpsertNovedadDto) {
    if (!dto.titulo?.trim()) throw new BadRequestException('El título es obligatorio');
    const row = await this.prisma.ecommerce_novedades.create({
      data: {
        empresa_id: empresaId,
        tipo: dto.tipo ?? 'anuncio',
        titulo: dto.titulo.trim(),
        descripcion: dto.descripcion?.trim() ?? null,
        tag: dto.tag?.trim() ?? null,
        cta_label: dto.cta_label?.trim() ?? null,
        target_category: dto.target_category?.trim() ?? null,
        imagen_url: dto.imagen_url?.trim() || null,
        prioridad: dto.prioridad ?? 10,
        activo: dto.activo ?? true,
      },
    });
    return this.serialize(row);
  }

  async update(empresaId: string, id: string, dto: UpsertNovedadDto) {
    await this.assertOwnership(id, empresaId);
    const row = await this.prisma.ecommerce_novedades.update({
      where: { id },
      data: {
        ...(dto.tipo !== undefined && { tipo: dto.tipo }),
        ...(dto.titulo !== undefined && { titulo: dto.titulo.trim() }),
        ...(dto.descripcion !== undefined && { descripcion: dto.descripcion?.trim() ?? null }),
        ...(dto.tag !== undefined && { tag: dto.tag?.trim() ?? null }),
        ...(dto.cta_label !== undefined && { cta_label: dto.cta_label?.trim() ?? null }),
        ...(dto.target_category !== undefined && { target_category: dto.target_category?.trim() ?? null }),
        ...(dto.imagen_url !== undefined && { imagen_url: dto.imagen_url?.trim() || null }),
        ...(dto.prioridad !== undefined && { prioridad: dto.prioridad }),
        ...(dto.activo !== undefined && { activo: dto.activo }),
        updated_at: new Date(),
      },
    });
    return this.serialize(row);
  }

  async remove(empresaId: string, id: string) {
    const row = await this.assertOwnership(id, empresaId);
    if (row.imagen_url) {
      const key = this.keyFromUrl(row.imagen_url);
      if (key) await this.s3.send(new DeleteObjectCommand({ Bucket: this.bucket, Key: key })).catch(() => undefined);
    }
    await this.prisma.ecommerce_novedades.delete({ where: { id } });
    return { ok: true };
  }

  async uploadImage(empresaId: string, id: string, file: Express.Multer.File) {
    await this.assertOwnership(id, empresaId);
    if (!file?.buffer) throw new BadRequestException('Archivo inválido');

    const optimized = await sharp(file.buffer)
      .rotate()
      .resize({ width: 1200, withoutEnlargement: true })
      .webp({ quality: 82 })
      .toBuffer();

    const key = `ecommerce/novedades/${empresaId}/${id}.webp`;
    await this.s3.send(
      new PutObjectCommand({
        Bucket: this.bucket,
        Key: key,
        Body: optimized,
        ContentType: 'image/webp',
        ACL: 'public-read',
      }),
    );

    const imageUrl = `${this.publicBase}/${key}`;
    const row = await this.prisma.ecommerce_novedades.update({
      where: { id },
      data: { imagen_url: imageUrl, updated_at: new Date() },
    });
    return this.serialize(row);
  }

  async deleteImage(empresaId: string, id: string) {
    const row = await this.assertOwnership(id, empresaId);
    const key = row.imagen_url ? this.keyFromUrl(row.imagen_url) : null;
    if (key) await this.s3.send(new DeleteObjectCommand({ Bucket: this.bucket, Key: key })).catch(() => undefined);
    const updated = await this.prisma.ecommerce_novedades.update({
      where: { id },
      data: { imagen_url: null, updated_at: new Date() },
    });
    return this.serialize(updated);
  }

  /** Lista las novedades activas para la tienda pública. */
  async listActivas(empresaId: string) {
    const rows = await this.prisma.ecommerce_novedades.findMany({
      where: { empresa_id: empresaId, activo: true },
      orderBy: [{ prioridad: 'desc' }, { created_at: 'asc' }],
    });
    return rows.map((r) => ({
      id: r.id,
      type: r.tipo as string,
      title: r.titulo,
      description: r.descripcion ?? '',
      tag: r.tag ?? '',
      image: r.imagen_url ?? '',
      ctaLabel: r.cta_label ?? 'Ver más',
      targetCategory: r.target_category ?? undefined,
      priority: r.prioridad,
    }));
  }

  private async assertOwnership(id: string, empresaId: string) {
    const row = await this.prisma.ecommerce_novedades.findFirst({ where: { id, empresa_id: empresaId } });
    if (!row) throw new NotFoundException('Novedad no encontrada');
    return row;
  }

  private serialize(row: any) {
    return {
      id: row.id,
      tipo: row.tipo,
      titulo: row.titulo,
      descripcion: row.descripcion,
      tag: row.tag,
      imagen_url: row.imagen_url,
      cta_label: row.cta_label,
      target_category: row.target_category,
      prioridad: row.prioridad,
      activo: row.activo,
      created_at: row.created_at,
    };
  }

  private keyFromUrl(url: string): string | null {
    const base = this.publicBase;
    if (base && url.startsWith(base + '/')) return url.slice(base.length + 1);
    return null;
  }
}
