import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DataSource, Repository } from 'typeorm';
import { ContentBlock } from './content-block.entity';
import { CreateContentBlockDto, UpdateContentBlockDto } from './dto/content-block.dto';
import { ReorderItemDto } from '../common/dto/reorder.dto';

@Injectable()
export class ContentBlocksService {
  constructor(
    @InjectRepository(ContentBlock)
    private readonly repo: Repository<ContentBlock>,
    private readonly dataSource: DataSource,
  ) {}

  async create(dto: CreateContentBlockDto): Promise<ContentBlock> {
    const orderIndex = dto.orderIndex ?? (await this.nextOrderIndex(dto.activityId));
    return this.repo.save(this.repo.create({ ...dto, orderIndex }));
  }

  findByActivity(activityId: number): Promise<ContentBlock[]> {
    return this.repo.find({
      where: { activityId },
      order: { orderIndex: 'ASC', id: 'ASC' },
    });
  }

  findById(id: number): Promise<ContentBlock | null> {
    return this.repo.findOne({ where: { id } });
  }

  async update(id: number, dto: UpdateContentBlockDto): Promise<ContentBlock> {
    const block = await this.findById(id);
    if (!block) throw new NotFoundException('Content block not found');
    Object.assign(block, dto);
    return this.repo.save(block);
  }

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

  /** Applies a whole new ordering atomically so a partial failure cannot scramble a lesson. */
  async reorder(items: ReorderItemDto[]): Promise<void> {
    await this.dataSource.transaction(async (manager) => {
      for (const item of items) {
        await manager.update(ContentBlock, item.id, { orderIndex: item.orderIndex });
      }
    });
  }

  /** Duplicates every block of one activity onto another (used when cloning content). */
  async copyToActivity(sourceActivityId: number, targetActivityId: number): Promise<number> {
    const blocks = await this.findByActivity(sourceActivityId);
    if (blocks.length === 0) return 0;

    const copies = blocks.map((block) =>
      this.repo.create({
        activityId: targetActivityId,
        type: block.type,
        title: block.title,
        payload: block.payload,
        orderIndex: block.orderIndex,
      }),
    );
    await this.repo.save(copies);
    return copies.length;
  }

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