import 'dart:convert';

import 'package:flutter/services.dart' show rootBundle;

class BangladeshThana {
  final String name;
  final String bnName;
  final String slug;

  const BangladeshThana({
    required this.name,
    required this.bnName,
    required this.slug,
  });

  factory BangladeshThana.fromJson(Map<String, dynamic> json) {
    return BangladeshThana(
      name: json['name']?.toString() ?? '',
      bnName: json['bnName']?.toString() ?? '',
      slug: json['slug']?.toString() ?? '',
    );
  }
}

class BangladeshDistrict {
  final int id;
  final String name;
  final String bnName;
  final String slug;
  final List<BangladeshThana> thanas;

  const BangladeshDistrict({
    required this.id,
    required this.name,
    required this.bnName,
    required this.slug,
    required this.thanas,
  });

  factory BangladeshDistrict.fromJson(Map<String, dynamic> json) {
    final List<dynamic> rawThanas = json['thanas'] is List ? json['thanas'] : <dynamic>[];
    return BangladeshDistrict(
      id: int.tryParse(json['id']?.toString() ?? '') ?? 0,
      name: json['name']?.toString() ?? '',
      bnName: json['bnName']?.toString() ?? '',
      slug: json['slug']?.toString() ?? '',
      thanas: rawThanas
          .map((item) => BangladeshThana.fromJson(Map<String, dynamic>.from(item as Map)))
          .toList(),
    );
  }
}

class BangladeshAddressHelper {
  static const String country = 'Bangladesh';
  static const String countryCode = 'BD';
  static const String dialCode = '+880';
  static const String addressSource = 'manual_bd';
  static const String _assetPath = 'assets/json/bangladesh_districts_thanas.json';

  static List<BangladeshDistrict>? _cachedDistricts;

  static Future<List<BangladeshDistrict>> getDistricts() async {
    if (_cachedDistricts != null) {
      return _cachedDistricts!;
    }

    final String rawJson = await rootBundle.loadString(_assetPath);
    final List<dynamic> decoded = jsonDecode(rawJson) as List<dynamic>;
    _cachedDistricts = decoded
        .map((item) => BangladeshDistrict.fromJson(Map<String, dynamic>.from(item as Map)))
        .toList();
    return _cachedDistricts!;
  }

  static String normalizeValue(String? value) {
    return (value ?? '')
        .trim()
        .toLowerCase()
        .replaceAll(RegExp(r"['`’]"), '')
        .replaceAll(RegExp(r'[^a-z0-9]+'), ' ')
        .trim();
  }

  static BangladeshDistrict? findDistrict(
    List<BangladeshDistrict> districts,
    String? districtValue,
  ) {
    final String normalized = normalizeValue(districtValue);
    if (normalized.isEmpty) {
      return null;
    }

    for (final BangladeshDistrict district in districts) {
      if (normalizeValue(district.name) == normalized ||
          normalizeValue(district.slug) == normalized ||
          normalizeValue(district.bnName) == normalized) {
        return district;
      }
    }
    return null;
  }

  static BangladeshThana? findThana(
    List<BangladeshDistrict> districts,
    String? districtValue,
    String? thanaValue,
  ) {
    final BangladeshDistrict? district = findDistrict(districts, districtValue);
    final String normalized = normalizeValue(thanaValue);
    if (district == null || normalized.isEmpty) {
      return null;
    }

    for (final BangladeshThana thana in district.thanas) {
      if (normalizeValue(thana.name) == normalized ||
          normalizeValue(thana.slug) == normalized ||
          normalizeValue(thana.bnName) == normalized) {
        return thana;
      }
    }
    return null;
  }

  static List<String> getDistrictNames(List<BangladeshDistrict> districts) {
    return districts.map((district) => district.name).toList(growable: false);
  }

  static List<String> getThanaNames(
    List<BangladeshDistrict> districts,
    String? districtValue,
  ) {
    final BangladeshDistrict? district = findDistrict(districts, districtValue);
    if (district == null) {
      return <String>[];
    }

    return district.thanas.map((thana) => thana.name).toList(growable: false);
  }

  static List<String> filterNames(List<String> names, String pattern) {
    final String normalizedPattern = normalizeValue(pattern);
    if (normalizedPattern.isEmpty) {
      return names.take(20).toList();
    }

    return names
        .where((name) => normalizeValue(name).contains(normalizedPattern))
        .take(20)
        .toList();
  }

  static String buildManualAddress({
    String? additionalAddress,
    String? house,
    String? road,
    String? thana,
    String? district,
    String? fallbackAddress,
  }) {
    final List<String> parts = <String>[
      if ((additionalAddress ?? '').trim().isNotEmpty)
        additionalAddress!.trim(),
      if ((house ?? '').trim().isNotEmpty) house!.trim(),
      if ((road ?? '').trim().isNotEmpty) road!.trim(),
      if ((thana ?? '').trim().isNotEmpty) thana!.trim(),
      if ((district ?? '').trim().isNotEmpty) district!.trim(),
    ];

    if ((additionalAddress ?? '').trim().isEmpty &&
        parts.length == 1 &&
        (fallbackAddress ?? '').trim().isNotEmpty) {
      return fallbackAddress!.trim();
    }

    return parts.join(', ');
  }
}
