import { ForbiddenException, Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Drawing } from './drawing.entity';
import { SaveDrawingDto, UpdateDrawingDto } from './dto/drawing.dto';

@Injectable()
export class DrawingsService {
  constructor(
    @InjectRepository(Drawing)
    private readonly repo: Repository<Drawing>,
  ) {}

  /**
   * One drawing per (session, activity): re-saving the same activity updates
   * the existing record so "continue later" resumes rather than duplicates.
   */
  async save(dto: SaveDrawingDto): Promise<Drawing> {
    if (dto.activityId) {
      const existing = await this.repo.findOne({
        where: {
          anonymousSessionId: dto.anonymousSessionId,
          activityId: dto.activityId,
        },
      });
      if (existing) {
        Object.assign(existing, dto);
        return this.repo.save(existing);
      }
    }
    return this.repo.save(this.repo.create(dto));
  }

  async update(id: number, dto: UpdateDrawingDto): Promise<Drawing> {
    const drawing = await this.repo.findOne({ where: { id } });
    if (!drawing) throw new NotFoundException('Drawing not found');
    this.assertOwner(drawing, dto.anonymousSessionId);

    Object.assign(drawing, dto);
    return this.repo.save(drawing);
  }

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

  findBySession(sessionId: string): Promise<Drawing[]> {
    return this.repo.find({
      where: { anonymousSessionId: sessionId },
      order: { updatedAt: 'DESC' },
    });
  }

  findForActivity(sessionId: string, activityId: number): Promise<Drawing | null> {
    return this.repo.findOne({
      where: { anonymousSessionId: sessionId, activityId },
      relations: ['template'],
    });
  }

  async delete(id: number, sessionId: string): Promise<boolean> {
    const drawing = await this.repo.findOne({ where: { id } });
    if (!drawing) return false;
    this.assertOwner(drawing, sessionId);

    const result = await this.repo.delete(id);
    return (result.affected || 0) > 0;
  }

  count(): Promise<number> {
    return this.repo.count();
  }

  /** Learner content is scoped to its anonymous session - there is no other owner. */
  private assertOwner(drawing: Drawing, sessionId: string): void {
    if (drawing.anonymousSessionId !== sessionId) {
      throw new ForbiddenException('This drawing belongs to a different session');
    }
  }
}
