import { ConflictException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DataSource, Repository } from 'typeorm';
import { Section } from './section.entity';
import { CreateSectionDto } from './dto/create-section.dto';
import { UpdateSectionDto } from './dto/update-section.dto';
import { ReorderItemDto } from '../common/dto/reorder.dto';

@Injectable()
export class SectionsService {
  constructor(
    @InjectRepository(Section)
    private readonly sectionsRepo: Repository<Section>,
    private readonly dataSource: DataSource,
  ) {}

  async create(dto: CreateSectionDto): Promise<Section> {
    const existing = await this.sectionsRepo.findOne({ where: { slug: dto.slug } });
    if (existing) throw new ConflictException('A section with that slug already exists');

    const orderIndex = dto.orderIndex ?? (await this.nextOrderIndex());
    return this.sectionsRepo.save(this.sectionsRepo.create({ ...dto, orderIndex }));
  }

  findAll(status?: string): Promise<Section[]> {
    return this.sectionsRepo.find({
      where: status ? { status } : {},
      order: { orderIndex: 'ASC', id: 'ASC' },
    });
  }

  findAllPublished(): Promise<Section[]> {
    return this.sectionsRepo.find({
      where: { status: 'PUBLISHED' },
      order: { orderIndex: 'ASC' },
    });
  }

  findById(id: number): Promise<Section | null> {
    return this.sectionsRepo.findOne({ where: { id }, relations: ['modules'] });
  }

  async update(id: number, dto: UpdateSectionDto): Promise<Section | null> {
    if (dto.slug) {
      const clash = await this.sectionsRepo.findOne({ where: { slug: dto.slug } });
      if (clash && Number(clash.id) !== Number(id)) {
        throw new ConflictException('A section with that slug already exists');
      }
    }
    await this.sectionsRepo.update(id, dto);
    return this.findById(id);
  }

  async delete(id: number): Promise<boolean> {
    const result = await this.sectionsRepo.delete(id);
    return (result.affected || 0) > 0;
  }

  async setStatus(id: number, status: string): Promise<Section | null> {
    await this.sectionsRepo.update(id, { status });
    return this.findById(id);
  }

  publish(id: number): Promise<Section | null> {
    return this.setStatus(id, 'PUBLISHED');
  }

  archive(id: number): Promise<Section | null> {
    return this.setStatus(id, 'ARCHIVED');
  }

  async reorder(items: ReorderItemDto[]): Promise<void> {
    await this.dataSource.transaction(async (manager) => {
      for (const item of items) {
        await manager.update(Section, item.id, { orderIndex: item.orderIndex });
      }
    });
  }

  private async nextOrderIndex(): Promise<number> {
    const last = await this.sectionsRepo.findOne({
      where: {},
      order: { orderIndex: 'DESC' },
    });
    return last ? last.orderIndex + 1 : 0;
  }
}
