import {
  ForbiddenException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { DesignTemplateScope, UserRole } from '@prisma/client';
import { PrismaService } from '../../database/prisma.service';
import { CreateTemplateDto } from './dto/create-template.dto';
import { UpdateTemplateDto } from './dto/update-template.dto';
import { UploadsService } from '../uploads/uploads.service';

type RequestUser = {
  id: string;
  role: UserRole;
  shopId: string | null;
};

@Injectable()
export class TemplatesService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly uploads: UploadsService,
  ) {}

  private async assertCanAccessShop(user: RequestUser, shopId: string) {
    if (user.role === UserRole.SUPERADMIN) return;
    if (!user.shopId || user.shopId !== shopId)
      throw new ForbiddenException('Forbidden');

    if (user.role === UserRole.ADMIN) {
      const shop = await this.prisma.shop.findUnique({
        where: { id: shopId },
        select: { adminId: true },
      });
      if (!shop) throw new NotFoundException('Shop not found');
      if (shop.adminId !== user.id) throw new ForbiddenException('Forbidden');
    }
  }

  async list(
    user: RequestUser,
    scope?: DesignTemplateScope,
    shopIdQuery?: string,
  ) {
    if (user.role === UserRole.SUPERADMIN) {
      const where: any = {};
      if (shopIdQuery) where.shopId = shopIdQuery;
      if (scope) where.scope = scope;
      return this.prisma.designTemplate.findMany({
        where,
        orderBy: { createdAt: 'desc' },
      });
    }

    if (!user.shopId) throw new ForbiddenException('No shop selected');
    await this.assertCanAccessShop(user, user.shopId);

    const where: any = { shopId: user.shopId };
    if (scope) where.scope = scope;
    return this.prisma.designTemplate.findMany({
      where,
      orderBy: { createdAt: 'desc' },
    });
  }

  async create(user: RequestUser, dto: CreateTemplateDto) {
    if (!user.shopId) throw new ForbiddenException('No shop selected');
    await this.assertCanAccessShop(user, user.shopId);
    const created = await this.prisma.designTemplate.create({
      data: {
        shopId: user.shopId,
        name: dto.name,
        scope: dto.scope,
        design: dto.design as any,
      },
    });
    const rewritten = await this.uploads.rewriteDesignAssets(
      user.shopId,
      created.design as any,
      {
        bgRelDir: `shops/${user.shopId}/templates/${created.id}/background`,
        stickerRelDir: `shops/${user.shopId}/templates/${created.id}/sticker`,
      },
    );
    if (rewritten !== created.design) {
      return this.prisma.designTemplate.update({
        where: { id: created.id },
        data: { design: rewritten as any },
      });
    }
    return created;
  }

  async update(user: RequestUser, id: string, dto: UpdateTemplateDto) {
    const existing = await this.prisma.designTemplate.findUnique({
      where: { id },
      select: { id: true, shopId: true },
    });
    if (!existing) throw new NotFoundException('Template not found');
    await this.assertCanAccessShop(user, existing.shopId);
    const nextDesign =
      dto.design !== undefined
        ? await this.uploads.rewriteDesignAssets(
            existing.shopId,
            dto.design as any,
            {
              bgRelDir: `shops/${existing.shopId}/templates/${existing.id}/background`,
              stickerRelDir: `shops/${existing.shopId}/templates/${existing.id}/sticker`,
            },
          )
        : undefined;
    return this.prisma.designTemplate.update({
      where: { id },
      data: {
        ...(dto.name !== undefined ? { name: dto.name } : {}),
        ...(dto.scope !== undefined ? { scope: dto.scope } : {}),
        ...(dto.design !== undefined ? { design: nextDesign as any } : {}),
      },
    });
  }

  async remove(user: RequestUser, id: string) {
    const existing = await this.prisma.designTemplate.findUnique({
      where: { id },
      select: { id: true, shopId: true },
    });
    if (!existing) throw new NotFoundException('Template not found');
    await this.assertCanAccessShop(user, existing.shopId);
    await this.prisma.designTemplate.delete({ where: { id } });
    return { ok: true };
  }
}
