import 'package:superport/data/models/company/company_dto.dart';
import 'package:superport/domain/entities/company_hierarchy.dart';

/// Company 계층 구조 검증 유틸리티
class HierarchyValidator {
  static const int maxHierarchyDepth = 5;

  /// 순환 참조 검증
  static HierarchyValidationResult validateCircularReference({
    required int companyId,
    required int? newParentId,
    required List<CompanyDto> allCompanies,
  }) {
    if (newParentId == null) {
      return HierarchyValidationResult.valid();
    }

    // 자기 자신을 부모로 설정하려는 경우
    if (companyId == newParentId) {
      return HierarchyValidationResult.invalid(
        message: '회사는 자기 자신을 상위 회사로 설정할 수 없습니다.',
        errors: ['Self-reference detected'],
      );
    }

    // 자손을 부모로 설정하려는 경우 검증
    final descendants = _getDescendants(companyId, allCompanies);
    if (descendants.contains(newParentId)) {
      return HierarchyValidationResult.invalid(
        message: '하위 회사를 상위 회사로 설정할 수 없습니다. 순환 참조가 발생합니다.',
        errors: ['Circular reference detected'],
      );
    }

    return HierarchyValidationResult.valid();
  }

  /// 계층 깊이 검증
  static HierarchyValidationResult validateDepth({
    required int? parentId,
    required List<CompanyDto> allCompanies,
  }) {
    if (parentId == null) {
      return HierarchyValidationResult.valid();
    }

    final depth = _calculateDepth(parentId, allCompanies);
    if (depth >= maxHierarchyDepth) {
      return HierarchyValidationResult.invalid(
        message: '최대 계층 깊이($maxHierarchyDepth 레벨)를 초과했습니다.',
        errors: ['Maximum hierarchy depth exceeded'],
        warnings: ['Current depth: $depth'],
      );
    }

    return HierarchyValidationResult.valid();
  }

  /// 삭제 가능 여부 검증
  static HierarchyValidationResult validateDeletion({
    required int companyId,
    required List<CompanyDto> allCompanies,
  }) {
    final children = _getDirectChildren(companyId, allCompanies);
    
    if (children.isNotEmpty) {
      return HierarchyValidationResult.invalid(
        message: '하위 회사가 있는 회사는 삭제할 수 없습니다. 먼저 하위 회사를 이동하거나 삭제하세요.',
        errors: ['Cannot delete company with children'],
        warnings: ['${children.length} child companies found'],
      );
    }

    return HierarchyValidationResult.valid();
  }

  /// 부모 변경 가능 여부 검증
  static HierarchyValidationResult validateParentChange({
    required int companyId,
    required int? newParentId,
    required List<CompanyDto> allCompanies,
  }) {
    // 순환 참조 검증
    final circularResult = validateCircularReference(
      companyId: companyId,
      newParentId: newParentId,
      allCompanies: allCompanies,
    );
    
    if (!circularResult.isValid) {
      return circularResult;
    }

    // 계층 깊이 검증
    if (newParentId != null) {
      final depthResult = validateDepth(
        parentId: newParentId,
        allCompanies: allCompanies,
      );
      
      if (!depthResult.isValid) {
        return depthResult;
      }

      // 새 부모의 자손들 깊이 검증
      final descendants = _getDescendants(companyId, allCompanies);
      
      if (descendants.isNotEmpty) {
        final maxDescendantDepth = _getMaxDescendantDepth(companyId, allCompanies);
        final newParentDepth = _calculateDepth(newParentId, allCompanies);
        
        if (newParentDepth + maxDescendantDepth + 1 > maxHierarchyDepth) {
          return HierarchyValidationResult.invalid(
            message: '이동 시 하위 회사들이 최대 깊이를 초과하게 됩니다.',
            errors: ['Would exceed maximum depth after move'],
            warnings: ['New total depth: ${newParentDepth + maxDescendantDepth + 1}'],
          );
        }
      }
    }

    return HierarchyValidationResult.valid();
  }

  /// 계층 구조 트리 생성
  static CompanyHierarchy buildHierarchyTree({
    required List<CompanyDto> companies,
    int? rootParentId,
  }) {
    // 루트 회사들 찾기
    final rootCompanies = companies.where((c) => c.parentCompanyId == rootParentId).toList();
    
    if (rootCompanies.isEmpty) {
      return const CompanyHierarchy(
        id: '0',
        name: 'Root',
        children: [],
      );
    }

    // 트리 구축
    final children = rootCompanies
        .map((company) => _buildCompanyNode(company, companies, 0))
        .toList();

    return CompanyHierarchy(
      id: '0',
      name: 'Root',
      children: children,
      totalDescendants: _countAllDescendants(children),
    );
  }

  /// 회사 노드 생성 (재귀)
  static CompanyHierarchy _buildCompanyNode(
    CompanyDto company,
    List<CompanyDto> allCompanies,
    int level,
  ) {
    final children = allCompanies
        .where((c) => c.parentCompanyId == company.id)
        .map((child) => _buildCompanyNode(child, allCompanies, level + 1))
        .toList();

    final path = _buildPath(company.id ?? 0, allCompanies);

    return CompanyHierarchy(
      id: company.id.toString(),
      name: company.name,
      parentId: company.parentCompanyId?.toString(),
      children: children,
      level: level,
      fullPath: path,
      totalDescendants: _countAllDescendants(children),
    );
  }

  /// 자손 회사 목록 가져오기
  static List<int> _getDescendants(int companyId, List<CompanyDto> allCompanies) {
    final descendants = <int>[];
    final directChildren = _getDirectChildren(companyId, allCompanies);
    
    for (final childId in directChildren) {
      descendants.add(childId);
      descendants.addAll(_getDescendants(childId, allCompanies));
    }
    
    return descendants;
  }

  /// 직접 자식 회사 목록 가져오기
  static List<int> _getDirectChildren(int companyId, List<CompanyDto> allCompanies) {
    return allCompanies
        .where((c) => c.parentCompanyId == companyId)
        .map((c) => c.id ?? 0)
        .where((id) => id > 0)
        .toList();
  }

  /// 계층 깊이 계산
  static int _calculateDepth(int companyId, List<CompanyDto> allCompanies) {
    int depth = 0;
    int? currentId = companyId;
    
    while (currentId != null && depth < maxHierarchyDepth + 1) {
      final company = allCompanies.firstWhere(
        (c) => c.id == currentId,
        orElse: () => CompanyDto(
          id: 0,
          name: '',
          contactName: '',
          contactPhone: '',
          contactEmail: '',
          address: '', // 필수 필드 추가
          isActive: false,
          registeredAt: DateTime.now(), // createdAt → registeredAt
        ),
      );
      
      if (company.id == 0) break;
      
      currentId = company.parentCompanyId;
      if (currentId != null) {
        depth++;
      }
    }
    
    return depth;
  }

  /// 자손 최대 깊이 계산
  static int _getMaxDescendantDepth(int companyId, List<CompanyDto> allCompanies) {
    final directChildren = _getDirectChildren(companyId, allCompanies);
    
    if (directChildren.isEmpty) {
      return 0;
    }
    
    int maxDepth = 0;
    for (final childId in directChildren) {
      final childDepth = 1 + _getMaxDescendantDepth(childId, allCompanies);
      if (childDepth > maxDepth) {
        maxDepth = childDepth;
      }
    }
    
    return maxDepth;
  }

  /// 경로 생성
  static String _buildPath(int companyId, List<CompanyDto> allCompanies) {
    final path = <String>[];
    int? currentId = companyId;
    
    while (currentId != null) {
      final company = allCompanies.firstWhere(
        (c) => c.id == currentId,
        orElse: () => CompanyDto(
          id: 0,
          name: '',
          contactName: '',
          contactPhone: '',
          contactEmail: '',
          address: '', // 필수 필드 추가
          isActive: false,
          registeredAt: DateTime.now(), // createdAt → registeredAt
        ),
      );
      
      if (company.id == 0) break;
      
      path.insert(0, company.name);
      currentId = company.parentCompanyId;
    }
    
    return '/${path.join('/')}';
  }

  /// 모든 자손 수 계산
  static int _countAllDescendants(List<CompanyHierarchy> children) {
    int count = children.length;
    
    for (final child in children) {
      count += child.totalDescendants;
    }
    
    return count;
  }

  /// 계층 구조 일관성 검증
  static HierarchyValidationResult validateConsistency({
    required List<CompanyDto> allCompanies,
  }) {
    final errors = <String>[];
    final warnings = <String>[];
    
    for (final company in allCompanies) {
      // 부모가 존재하는지 확인
      if (company.parentCompanyId != null) {
        final parentExists = allCompanies.any((c) => c.id == company.parentCompanyId);
        if (!parentExists) {
          errors.add('Company ${company.id} references non-existent parent ${company.parentCompanyId}');
        }
      }
      
      // 순환 참조 확인
      final visited = <int>{};
      int? currentId = company.parentCompanyId;
      
      while (currentId != null) {
        if (visited.contains(currentId)) {
          errors.add('Circular reference detected starting from company ${company.id}');
          break;
        }
        
        visited.add(currentId);
        final parent = allCompanies.firstWhere(
          (c) => c.id == currentId,
          orElse: () => CompanyDto(
            id: 0,
            name: '',
            contactName: '',
            contactPhone: '',
            contactEmail: '',
            address: '',
            isActive: false,
            registeredAt: DateTime.now(),
          ),
        );
        
        currentId = parent.id == 0 ? null : parent.parentCompanyId;
      }
    }
    
    if (errors.isNotEmpty) {
      return HierarchyValidationResult.invalid(
        message: '계층 구조에 일관성 문제가 발견되었습니다.',
        errors: errors,
        warnings: warnings,
      );
    }
    
    return HierarchyValidationResult.valid();
  }
}