import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { Prisma } from '../../generated/prisma/client.js';
import { PrismaService } from '../../database/prisma.service.js';
import {
  boolean,
  integer,
  optionalText,
  optionalUrl,
  record,
  text,
} from '../../common/validation.js';

function slideInput(value: unknown, partial = false) {
  const data = record(value);
  const has = (key: string) => !partial || key in data;
  const result: Partial<Prisma.HeroSlideCreateInput> = {};
  if (has('title')) result.title = text(data.title, 'Headline', 160);
  if (has('subtitle')) result.subtitle = optionalText(data.subtitle, 'Sub-heading', 300);
  if (has('imageUrl')) {
    const imageUrl = optionalUrl(data.imageUrl, 'Banner image');
    if (!imageUrl) throw new BadRequestException('Upload a banner image.');
    result.imageUrl = imageUrl;
  }
  if (has('linkUrl')) result.linkUrl = optionalUrl(data.linkUrl, 'Link');
  if (has('buttonLabel')) result.buttonLabel = optionalText(data.buttonLabel, 'Button label', 60);
  if (has('sortOrder')) {
    result.sortOrder = data.sortOrder === undefined ? 0 : integer(data.sortOrder, 'Sort order', 0, 9999);
  }
  if (has('active')) result.active = data.active === undefined ? true : boolean(data.active, 'Active');
  return result;
}

@Injectable()
export class SlidesService {
  constructor(private readonly prisma: PrismaService) {}

  list(activeOnly = false) {
    return this.prisma.heroSlide.findMany({
      where: activeOnly ? { active: true } : undefined,
      orderBy: [{ sortOrder: 'asc' }, { id: 'asc' }],
    });
  }

  create(value: unknown) {
    return this.prisma.heroSlide.create({
      data: slideInput(value) as Prisma.HeroSlideCreateInput,
    });
  }

  async update(id: number, value: unknown) {
    try {
      return await this.prisma.heroSlide.update({ where: { id }, data: slideInput(value, true) });
    } catch (error) {
      this.notFound(error);
    }
  }

  async remove(id: number) {
    try {
      await this.prisma.heroSlide.delete({ where: { id } });
      return { success: true };
    } catch (error) {
      this.notFound(error);
    }
  }

  private notFound(error: unknown): never {
    if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2025') {
      throw new NotFoundException('Banner not found.');
    }
    throw error;
  }
}
