import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, IsNull, ILike, FindOptionsWhere } from 'typeorm';
import { MasterQuestion } from 'src/common/entities/master-question.entity';
import { CommonDataService } from 'src/common/services/commonData.service';
import { handleKnownErrors } from 'src/common/utils/handle-error.util';
import { ERROR_CODES } from 'src/common/constants/error-string-constants';
import { CreateMasterQuestionDto } from './dto/create-master-question.dto';
import { UpdateMasterQuestionDto } from './dto/update-master-question.dto';
import { FilterMasterQuestionDto } from './dto/filter-master-question.dto';

@Injectable()
export class MasterQuestionRepository {
  constructor(
    @InjectRepository(MasterQuestion)
    private readonly masterQuestionRepo: Repository<MasterQuestion>,
    private readonly commonDataService: CommonDataService,
  ) {}

  /**
   * Find all master questions with pagination and filters
   */
  async findAll(filters: FilterMasterQuestionDto) {
    try {
      const { limit = 10, offset = 0, searchText, isActive, masterFormSectionId, questionType, answerType } = filters;

      // Use query builder for complex queries with joins to filter deleted sections
      const queryBuilder = this.masterQuestionRepo
        .createQueryBuilder('mq')
        .leftJoinAndSelect('mq.masterFormSection', 'mfs')
        .where('mq.deletedAt IS NULL')
        .andWhere('(mfs.deletedAt IS NULL OR mfs.id IS NULL)'); // Filter out questions from deleted sections

      if (searchText) {
        queryBuilder.andWhere('mq.questionText ILIKE :searchText', { searchText: `%${searchText}%` });
      }

      if (isActive !== undefined) {
        queryBuilder.andWhere('mq.isActive = :isActive', { isActive });
      }

      if (masterFormSectionId !== undefined) {
        queryBuilder.andWhere('mq.masterFormSectionId = :masterFormSectionId', { masterFormSectionId });
      }

      if (questionType) {
        queryBuilder.andWhere('mq.questionType = :questionType', { questionType });
      }

      if (answerType) {
        queryBuilder.andWhere('mq.answerType = :answerType', { answerType });
      }

      const total = await queryBuilder.getCount();
      const data = await queryBuilder
        .orderBy('mq.id', 'ASC')
        .skip(offset)
        .take(limit)
        .getMany();

      const totalPages = Math.ceil(total / limit);

      return {
        data,
        pagination: {
          totalPages,
          pageNumber: Math.floor(offset / limit) + 1,
          pageSize: +limit,
          totalRecords: total,
        },
      };
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_QUESTION_FIND_FAILED, error);
    }
  }

  /**
   * Find a master question by ID
   */
  async findById(id: number): Promise<MasterQuestion | null> {
    try {
      return await this.masterQuestionRepo.findOne({
        where: { id, deletedAt: IsNull() },
        relations: ['masterFormSection'],
      });
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_QUESTION_FIND_BY_ID_FAILED, error);
    }
  }

  /**
   * Find a master question by question code
   */
  async findByQuestionCode(questionCode: string): Promise<MasterQuestion | null> {
    try {
      return await this.masterQuestionRepo.findOne({
        where: { questionCode, deletedAt: IsNull() },
      });
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_QUESTION_FIND_BY_CODE_FAILED, error);
    }
  }

  /**
   * Find questions by section ID
   */
  async findBySection(sectionId: number): Promise<MasterQuestion[]> {
    try {
      return await this.masterQuestionRepo.find({
        where: { masterFormSectionId: sectionId, deletedAt: IsNull(), isActive: true },
        order: { id: 'ASC' },
      });
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_QUESTION_FIND_BY_SECTION_FAILED, error);
    }
  }

  /**
   * Create a new master question
   */
  async create(createDto: CreateMasterQuestionDto): Promise<MasterQuestion> {
    try {
      const now = new Date();
      const newQuestion = this.masterQuestionRepo.create({
        ...createDto,
        isActive: createDto.isActive ?? true,
        createdAt: now,
        updatedAt: now,
      });
      return await this.masterQuestionRepo.save(newQuestion);
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_QUESTION_CREATE_FAILED, error);
    }
  }

  /**
   * Update a master question
   */
  async update(id: number, updateDto: UpdateMasterQuestionDto): Promise<MasterQuestion | null> {
    try {
      await this.masterQuestionRepo.update(id, updateDto);
      return await this.findById(id);
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_QUESTION_UPDATE_FAILED, error);
    }
  }

  /**
   * Soft delete a master question
   */
  async softDelete(id: number, userId?: number): Promise<boolean> {
    try {
      // Update the updatedBy field before soft deleting if userId is provided
      if (userId) {
        await this.masterQuestionRepo.update(id, { updatedBy: userId });
      }
      const result = await this.masterQuestionRepo.softDelete(id);
      return (result.affected ?? 0) > 0;
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_QUESTION_DELETE_FAILED, error);
    }
  }
}
