import { Injectable } from '@nestjs/common';
import { MasterFormSectionRepository } from './master-form-section.repository';
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';
import { InifniNotFoundException } from 'src/common/exceptions/infini-notfound-exception';
import InifniBadRequestException from 'src/common/exceptions/infini-badrequest-exception';
import { ERROR_CODES } from 'src/common/constants/error-string-constants';
import { AppLoggerService } from 'src/common/services/logger.service';
import { handleKnownErrors } from 'src/common/utils/handle-error.util';

@Injectable()
export class MasterFormSectionService {
  constructor(
    private readonly masterFormSectionRepo: MasterFormSectionRepository,
    private readonly logger: AppLoggerService,
  ) {}

  /**
   * Get all master form sections with filters
   */
  async findAll(filters: FilterMasterFormSectionDto) {
    try {
      this.logger.log('Finding all master form sections', { filters });
      return await this.masterFormSectionRepo.findAll(filters);
    } catch (error) {
      this.logger.error('Error finding master form sections', error);
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_FIND_FAILED, error);
    }
  }

  /**
   * Get a single master form section by ID
   */
  async findById(id: number) {
    try {
      this.logger.log('Finding master form section by ID', { id });
      const section = await this.masterFormSectionRepo.findById(id);
      
      if (!section) {
        handleKnownErrors(
          ERROR_CODES.MASTER_FORM_SECTION_NOT_FOUND,
          new Error(`Master form section not found: ${id}`)
        );
      }

      return section;
    } catch (error) {
      this.logger.error('Error finding master form section by ID', error);
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_FIND_BY_ID_FAILED, error);
    }
  }

  /**
   * Get section hierarchy (tree structure)
   */
  async getHierarchy() {
    try {
      this.logger.log('Getting master form section hierarchy');
      return await this.masterFormSectionRepo.findHierarchy();
    } catch (error) {
      this.logger.error('Error getting section hierarchy', error);
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_HIERARCHY_FAILED, error);
    }
  }

  /**
   * Get subsections of a section
   */
  async getChildren(parentId: number) {
    try {
      this.logger.log('Getting subsections of section', { parentId });
      
      // Verify parent exists
      await this.findById(parentId);
      
      return await this.masterFormSectionRepo.findChildren(parentId);
    } catch (error) {
      this.logger.error('Error getting section subsections', error);
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_CHILDREN_FAILED, error);
    }
  }

  /**
   * Get ancestors of a section (breadcrumb)
   */
  async getAncestors(sectionId: number) {
    try {
      this.logger.log('Getting ancestors of section', { sectionId });
      
      // Verify section exists
      const section = await this.findById(sectionId);
      
      const ancestors = await this.masterFormSectionRepo.findAncestors(sectionId);
      
      return {
        section,
        ancestors,
        breadcrumb: [...ancestors.map(a => a.name), section.name],
      };
    } catch (error) {
      this.logger.error('Error getting section ancestors', error);
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_ANCESTORS_FAILED, error);
    }
  }

  /**
   * Create a new master form section
   */
  async create(createDto: CreateMasterFormSectionDto) {
    try {
      this.logger.log('Creating master form section', { createDto });

      // Check if section key already exists
      const existing = await this.masterFormSectionRepo.findBySectionKey(createDto.sectionKey);
      if (existing) {
        handleKnownErrors(
          ERROR_CODES.MASTER_FORM_SECTION_KEY_EXISTS,
          new Error(`Section key already exists: ${createDto.sectionKey}`)
        );
      }

      // Validate parent section if provided
      if (createDto.parentSectionId) {
        await this.findById(createDto.parentSectionId);
      }

      return await this.masterFormSectionRepo.create(createDto);
    } catch (error) {
      this.logger.error('Error creating master form section', error);
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_CREATE_FAILED, error);
    }
  }

  /**
   * Create a subsection under a parent
   */
  async createSubsection(parentId: number, createDto: CreateMasterFormSectionDto) {
    try {
      this.logger.log('Creating subsection', { parentId, createDto });

      // Verify parent exists
      await this.findById(parentId);

      // Set parent ID
      createDto.parentSectionId = parentId;

      return await this.create(createDto);
    } catch (error) {
      this.logger.error('Error creating subsection', error);
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_CREATE_FAILED, error);
    }
  }

  /**
   * Update a master form section
   */
  async update(id: number, updateDto: UpdateMasterFormSectionDto) {
    try {
      this.logger.log('Updating master form section', { id, updateDto });

      // Verify section exists
      await this.findById(id);

      // Validate parent section if provided
      if (updateDto.parentSectionId) {
        // Prevent self-reference
        if (updateDto.parentSectionId === id) {
          handleKnownErrors(
            ERROR_CODES.MASTER_FORM_SECTION_SELF_REFERENCE,
            new Error('Cannot set section as its own parent')
          );
        }
        await this.findById(updateDto.parentSectionId);
      }

      return await this.masterFormSectionRepo.update(id, updateDto);
    } catch (error) {
      this.logger.error('Error updating master form section', error);
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_UPDATE_FAILED, error);
    }
  }

  /**
   * Soft delete a master form section
   */
  async delete(id: number) {
    try {
      this.logger.log('Deleting master form section', { id });

      // Verify section exists
      await this.findById(id);

      // Check if section has subsections
      const children = await this.masterFormSectionRepo.findChildren(id);
      if (children && children.length > 0) {
        handleKnownErrors(
          ERROR_CODES.MASTER_FORM_SECTION_HAS_CHILDREN,
          new Error(`Cannot delete section ${id} that has subsections`)
        );
      }

      await this.masterFormSectionRepo.softDelete(id);
    } catch (error) {
      this.logger.error('Error deleting master form section', error);
      handleKnownErrors(ERROR_CODES.MASTER_FORM_SECTION_DELETE_FAILED, error);
    }
  }
}
