import '../../organization/domain/organization_models.dart';

class TenantNavigationModel {
  const TenantNavigationModel({
    required this.selectedTenant,
    required this.selectedCompanyTenant,
    required this.pinnedTenant,
    required this.companyTenants,
    required this.breadcrumbTenants,
    required this.visibleChips,
    required this.childTenants,
    required this.selectedTenantSubtreeSlugs,
  });

  final TenantSummary? selectedTenant;
  final TenantSummary? selectedCompanyTenant;
  final TenantSummary? pinnedTenant;
  final List<TenantSummary> companyTenants;
  final List<TenantSummary> breadcrumbTenants;
  final List<TenantSummary> visibleChips;
  final List<TenantSummary> childTenants;
  final List<String> selectedTenantSubtreeSlugs;

  bool get showsCompanyDirectory => selectedTenant == null;
  bool get hasChildren => childTenants.isNotEmpty;
}

TenantNavigationModel buildTenantNavigationModel({
  required List<TenantSummary> tenants,
  required String selectedTenantSlug,
  required String pinnedTenantSlug,
}) {
  final selectedTenant = _findTenantBySlug(tenants, selectedTenantSlug);
  final pinnedTenant = _findTenantBySlug(tenants, pinnedTenantSlug);
  final companyTenants = [
    for (final tenant in tenants)
      if (tenant.type == 'COMPANY') tenant,
  ];
  final breadcrumbTenants = selectedTenant == null
      ? const <TenantSummary>[]
      : _buildBreadcrumbTenants(tenants, selectedTenant);
  final selectedCompanyTenant = _resolveSelectedCompanyTenant(
    selectedTenant: selectedTenant,
    breadcrumbTenants: breadcrumbTenants,
  );
  final childTenants = selectedTenant == null
      ? companyTenants
      : [
          for (final tenant in tenants)
            if (tenant.parentId == selectedTenant.id) tenant,
        ];
  final selectedTenantSubtreeSlugs = selectedTenant == null
      ? const <String>[]
      : buildTenantSubtreeSlugs(tenants: tenants, rootTenant: selectedTenant);

  final visibleChips = <TenantSummary>[];
  final seenSlugs = <String>{};

  void addChip(TenantSummary tenant) {
    if (tenant.slug.trim().isEmpty || !seenSlugs.add(tenant.slug)) {
      return;
    }
    visibleChips.add(tenant);
  }

  for (final tenant in companyTenants) {
    addChip(tenant);
  }

  if (pinnedTenant != null && pinnedTenant.type != 'COMPANY') {
    addChip(pinnedTenant);
  }

  for (final tenant in breadcrumbTenants) {
    if (tenant.type != 'COMPANY') {
      addChip(tenant);
    }
  }

  return TenantNavigationModel(
    selectedTenant: selectedTenant,
    selectedCompanyTenant: selectedCompanyTenant,
    pinnedTenant: pinnedTenant,
    companyTenants: companyTenants,
    breadcrumbTenants: breadcrumbTenants,
    visibleChips: visibleChips,
    childTenants: childTenants,
    selectedTenantSubtreeSlugs: selectedTenantSubtreeSlugs,
  );
}

List<String> buildTenantSubtreeSlugs({
  required List<TenantSummary> tenants,
  required TenantSummary rootTenant,
}) {
  final tenantsByParentId = <String, List<TenantSummary>>{};
  for (final tenant in tenants) {
    final parentId = tenant.parentId;
    if (parentId == null || parentId.trim().isEmpty) {
      continue;
    }
    tenantsByParentId
        .putIfAbsent(parentId, () => <TenantSummary>[])
        .add(tenant);
  }

  final slugs = <String>[];
  final queue = <TenantSummary>[rootTenant];
  final visitedIds = <String>{};
  while (queue.isNotEmpty) {
    final current = queue.removeAt(0);
    if (!visitedIds.add(current.id)) {
      continue;
    }
    if (current.slug.trim().isNotEmpty) {
      slugs.add(current.slug);
    }
    queue.addAll(tenantsByParentId[current.id] ?? const <TenantSummary>[]);
  }
  return slugs;
}

String resolvePinnedTenantSlug({
  required List<TenantSummary> tenants,
  required String companySlug,
  required String? departmentName,
}) {
  final normalizedDepartment = departmentName?.trim();
  if (normalizedDepartment == null || normalizedDepartment.isEmpty) {
    return companySlug;
  }

  final companyTenant = _findTenantBySlug(tenants, companySlug);
  if (companyTenant == null) {
    return companySlug;
  }

  final match = _findDescendantTenantByName(
    tenants: tenants,
    rootTenantId: companyTenant.id,
    tenantName: normalizedDepartment,
  );
  return match?.slug ?? companySlug;
}

List<TenantSummary> _buildBreadcrumbTenants(
  List<TenantSummary> tenants,
  TenantSummary selectedTenant,
) {
  final tenantsById = {for (final tenant in tenants) tenant.id: tenant};
  final reversed = <TenantSummary>[selectedTenant];
  var current = selectedTenant;
  while (current.parentId != null && current.parentId!.trim().isNotEmpty) {
    final parent = tenantsById[current.parentId!];
    if (parent == null) {
      break;
    }
    reversed.add(parent);
    current = parent;
  }
  return reversed.reversed.toList(growable: false);
}

TenantSummary? _findTenantBySlug(List<TenantSummary> tenants, String slug) {
  for (final tenant in tenants) {
    if (tenant.slug == slug) {
      return tenant;
    }
  }
  return null;
}

TenantSummary? _resolveSelectedCompanyTenant({
  required TenantSummary? selectedTenant,
  required List<TenantSummary> breadcrumbTenants,
}) {
  if (selectedTenant == null) {
    return null;
  }
  if (selectedTenant.type == 'COMPANY') {
    return selectedTenant;
  }
  for (final tenant in breadcrumbTenants) {
    if (tenant.type == 'COMPANY') {
      return tenant;
    }
  }
  return null;
}

TenantSummary? _findDescendantTenantByName({
  required List<TenantSummary> tenants,
  required String rootTenantId,
  required String tenantName,
}) {
  final normalizedName = tenantName.trim().toLowerCase();
  if (normalizedName.isEmpty) {
    return null;
  }

  final tenantsByParentId = <String, List<TenantSummary>>{};
  for (final tenant in tenants) {
    final parentId = tenant.parentId;
    if (parentId == null || parentId.trim().isEmpty) {
      continue;
    }
    tenantsByParentId
        .putIfAbsent(parentId, () => <TenantSummary>[])
        .add(tenant);
  }

  final queue = <String>[rootTenantId];
  final visited = <String>{};
  while (queue.isNotEmpty) {
    final currentId = queue.removeAt(0);
    if (!visited.add(currentId)) {
      continue;
    }
    for (final tenant
        in tenantsByParentId[currentId] ?? const <TenantSummary>[]) {
      if (tenant.name.trim().toLowerCase() == normalizedName) {
        return tenant;
      }
      queue.add(tenant.id);
    }
  }
  return null;
}
