import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, IsNull, ILike, FindOptionsWhere } from 'typeorm';
import { MasterFormSection } from 'src/common/entities/master-form-section.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 { CreateMasterFormSectionDto } from './dto/create-master-form-section.dto';
import { UpdateMasterFormSectionDto } from './dto/update-master-form-section.dto';
import { FilterMasterFormSectionDto } from './dto/filter-master-form-section.dto';

@Injectable()
export class MasterFormSectionRepository {
  constructor(
    @InjectRepository(MasterFormSection)
    private readonly masterFormSectionRepo: Repository<MasterFormSection>,
    private readonly commonDataService: CommonDataService,
  ) {}

  /**
   * Find all master form sections with pagination and filters
   */
  async findAll(filters: FilterMasterFormSectionDto) {
    try {
      const { limit = 10, offset = 0, searchText, isActive, parentSectionId } = filters;

      const selectFields: (keyof MasterFormSection)[] = [
        'id',
        'sectionKey',
        'name',
        'description',
        'parentSectionId',
        'conditionalConfig',
        'isActive',
        'createdAt',
        'updatedAt',
        'createdBy',
        'updatedBy',
      ];

      const whereClause: FindOptionsWhere<MasterFormSection> = { deletedAt: IsNull() };

      if (searchText) {
        whereClause.name = ILike(`%${searchText}%`);
      }

      if (isActive !== undefined) {
        whereClause.isActive = isActive;
      }

      if (parentSectionId !== undefined) {
        whereClause.parentSectionId = parentSectionId === null ? IsNull() : parentSectionId;
      }

      const data = await this.commonDataService.get(
        this.masterFormSectionRepo,
        selectFields,
        whereClause,
        limit,
        offset,
        { id: 'ASC' },
      );

      const total = await this.masterFormSectionRepo.count({ where: whereClause });
      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_FORM_SECTION_FIND_FAILED, error);
    }
  }

  /**
   * Find a master form section by ID
   */
  async findById(id: number): Promise<MasterFormSection | null> {
    try {
      return await this.masterFormSectionRepo.findOne({
        where: { id, deletedAt: IsNull() },
        relations: ['parentSection', 'questions'],
      });
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_FIND_BY_ID_FAILED, error);
    }
  }

  /**
   * Find a master form section by section key
   */
  async findBySectionKey(sectionKey: string): Promise<MasterFormSection | null> {
    try {
      return await this.masterFormSectionRepo.findOne({
        where: { sectionKey, deletedAt: IsNull() },
      });
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_FIND_BY_KEY_FAILED, error);
    }
  }

  /**
   * Get hierarchy of sections (tree structure)
   */
  async findHierarchy(): Promise<MasterFormSection[]> {
    try {
      // Get all root sections (no parent)
      const rootSections = await this.masterFormSectionRepo.find({
        where: { parentSectionId: IsNull(), deletedAt: IsNull(), isActive: true },
        order: { id: 'ASC' },
      });

      // Recursively load subsections for each root section
      for (const section of rootSections) {
        await this.loadSubsections(section);
      }

      return rootSections;
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_HIERARCHY_FAILED, error);
    }
  }

  /**
   * Recursively load subsections
   */
  private async loadSubsections(section: MasterFormSection): Promise<void> {
    const subsections = await this.masterFormSectionRepo.find({
      where: { parentSectionId: section.id, deletedAt: IsNull(), isActive: true },
      order: { id: 'ASC' },
    });

    (section as any).subsections = subsections;

    for (const subsection of subsections) {
      await this.loadSubsections(subsection);
    }
  }

  /**
   * Get subsections of a specific section
   */
  async findChildren(parentId: number): Promise<MasterFormSection[]> {
    try {
      return await this.masterFormSectionRepo.find({
        where: { parentSectionId: parentId, deletedAt: IsNull(), isActive: true },
        order: { id: 'ASC' },
      });
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_CHILDREN_FAILED, error);
    }
  }

  /**
   * Get ancestors of a section (breadcrumb trail)
   */
  async findAncestors(sectionId: number): Promise<MasterFormSection[]> {
    try {
      const ancestors: MasterFormSection[] = [];
      let currentSection = await this.findById(sectionId);

      while (currentSection && currentSection.parentSectionId) {
        const parent = await this.findById(currentSection.parentSectionId);
        if (parent) {
          ancestors.unshift(parent);
          currentSection = parent;
        } else {
          break;
        }
      }

      return ancestors;
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_ANCESTORS_FAILED, error);
    }
  }

  /**
   * Create a new master form section
   */
  async create(createDto: CreateMasterFormSectionDto): Promise<MasterFormSection> {
    try {
      const now = new Date();
      const newSection = this.masterFormSectionRepo.create({
        ...createDto,
        isActive: createDto.isActive ?? true,
        createdAt: now,
        updatedAt: now,
      });
      return await this.masterFormSectionRepo.save(newSection);
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_CREATE_FAILED, error);
    }
  }

  /**
   * Update a master form section
   */
  async update(id: number, updateDto: UpdateMasterFormSectionDto): Promise<MasterFormSection | null> {
    try {
      await this.masterFormSectionRepo.update(id, updateDto);
      return await this.findById(id);
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_UPDATE_FAILED, error);
    }
  }

  /**
   * Soft delete a master form section
   */
  async softDelete(id: number): Promise<void> {
    try {
      await this.masterFormSectionRepo.softDelete(id);
    } catch (error) {
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_DELETE_FAILED, error);
    }
  }
}
