import {
  BadRequestException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { CreateChallengeDto } from './dto/create-challenge.dto';
import { UpdateChallengeDto } from './dto/update-challenge.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Challenge } from './entities/challenge.entity';
import { Repository } from 'typeorm';
import { ChallengesRepository } from './challenges.repository';
import { ChallengesMedia } from './entities/challenge_media.entity';
import { CreateChallengesImageDto } from './dto/create-challenge-image.dto';
import isValidUuidV4 from 'src/common/uuid validator/uuid-validate';
import { lan } from 'src/lan';
import { isEmpty } from 'src/common/helper';
import * as path from 'path';
import * as fs from 'fs';

@Injectable()
export class ChallengesService {
  constructor(
    @InjectRepository(Challenge)
    private readonly challengeEntity: Repository<Challenge>,
    private readonly challengeRepository: ChallengesRepository,
    @InjectRepository(ChallengesMedia)
    private readonly challengeMediaEntity: Repository<ChallengesMedia>,
  ) {}

  async create(
    createChallengeDto: CreateChallengeDto,
    createChallengesImageDto: CreateChallengesImageDto,
  ): Promise<ChallengesMedia[]> {
    const createChallenge: Challenge = new Challenge();
    Object.assign(createChallenge, createChallengeDto);

    await this.challengeEntity.save(createChallenge);
    const challengeObj = await this.challengeEntity.findOneBy({
      id: createChallenge.id,
    });

    const challengesImages: ChallengesMedia[] = [];

    for (const attachment of createChallengesImageDto.media) {
      const newsImage: ChallengesMedia = new ChallengesMedia();
      newsImage.media = attachment.path;
      newsImage.challenges_id = challengeObj.id;
      newsImage.media_type = attachment.mimetype[0];

      const savedImage = await this.challengeMediaEntity.save(newsImage);
      challengesImages.push(savedImage);
    }

    return challengesImages;
  }

  async findAllChallenges(
    take: number,
    skip: number,
    search: string,
    headers: any,
  ) {
    return await this.challengeRepository.findAll(take, skip, search, headers);
  }

  async findChallenge(id: string) {
    if (!isValidUuidV4(id)) {
      throw new BadRequestException(lan('common.invalid_uuid_format'));
    }

    const challenge = await this.challengeRepository.findOne(id);

    if (isEmpty(challenge)) {
      throw new NotFoundException(lan('common.data_not_found'));
    }

    return challenge;
  }

  async updateChallenge(
    id: string,
    updateChallengeDto: UpdateChallengeDto,
    updateChallengesImageDto: CreateChallengesImageDto,
  ): Promise<ChallengesMedia[]> {
    if (!isValidUuidV4(id)) {
      throw new BadRequestException(lan('common.invalid_uuid_format'));
    }

    const challenge = await this.challengeRepository.findOneById(id);

    if (isEmpty(challenge)) {
      throw new NotFoundException(lan('common.data_not_found'));
    }

    Object.assign(challenge, updateChallengeDto);

    const updatedChallenge = await this.challengeEntity.save(challenge);
    const challengeImages: ChallengesMedia[] = [];

    if (!isEmpty(updateChallengesImageDto)) {
      for (const attachment of updateChallengesImageDto.media) {
        let challengeImage = challenge.challenges_media.find(
          (img) => img.media === attachment.path,
        );

        if (isEmpty(challengeImage)) {
          challengeImage = new ChallengesMedia();
          challengeImage.media = attachment.path;
          challengeImage.challenges_id = updatedChallenge.id;
          challengeImage.media_type = attachment.mimetype[0];
        }

        const savedImage = await this.challengeMediaEntity.save(challengeImage);

        challengeImages.push(savedImage);
      }
    }

    return challengeImages;
  }

  async removeChallenge(id: string) {
    if (!isValidUuidV4(id)) {
      throw new BadRequestException(lan('common.invalid_uuid_format'));
    }

    const challenge = await this.challengeRepository.findOneById(id);

    if (isEmpty(challenge)) {
      throw new NotFoundException(lan('common.data_not_found'));
    }

    for (const image of challenge.challenges_media) {
      const filePath = path.join(`public/${image.media}`);

      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
      }
    }

    await this.challengeMediaEntity.softRemove(challenge.challenges_media);
    await this.challengeEntity.softDelete(id);
  }

  async deleteImage(challengeId: string, imageId: string): Promise<void> {
    const challenge = await this.challengeRepository.findOne(challengeId);

    if (isEmpty(challenge)) {
      throw new NotFoundException(lan('common.data_not_found'));
    }

    const image = challenge.challenges_media.find((img) => img.id === imageId);

    if (isEmpty(image)) {
      throw new NotFoundException(lan('common.data_not_found'));
    }

    await this.challengeMediaEntity.softDelete(imageId);
  }
}
