// ignore_for_file: use_build_context_synchronously
import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:kvwsmb_survey_app/Bloc/data_cubit.dart';
import 'package:kvwsmb_survey_app/constants/globals.dart';
import 'package:kvwsmb_survey_app/custom_properties/ecomi_object.dart';
import 'package:kvwsmb_survey_app/helper/convert_wkt_latlng.dart';

List<String> _filterKeys((List<String>, String) args) {
  final (keys, query) = args;
  return keys.where((key) => key.contains(query)).toList();
}

void openSearchDialog(
  DataCubit dataCubit,
  BuildContext context,
  List<Map<String, dynamic>> layerList,
  Map<String, List<Map<String, dynamic>>> attributeList,
  MapController mapController,
  double maxzoom,
  Function()? reloadFeatures,
) {
  showGeneralDialog(
    context: context,
    pageBuilder:
        (context, animation, secondaryAnimation) => SearchDialog(
          dataCubit: dataCubit,
          layerList: layerList,
          attributeList: attributeList,
          mapController: mapController,
          maxzoom: maxzoom,
          reloadFeatures: reloadFeatures,
        ),
    transitionBuilder: (context, animation, secondaryAnimation, child) {
      return Align(
        alignment: Alignment.topCenter,
        child: SlideTransition(
          position: Tween<Offset>(
            begin: const Offset(0, -0.1),
            end: Offset.zero,
          ).animate(animation),
          child: child,
        ),
      );
    },
    transitionDuration: const Duration(milliseconds: 200),
  );
}

class SearchDialog extends StatefulWidget {
  final DataCubit dataCubit;
  final List<Map<String, dynamic>> layerList;
  final Map<String, List<Map<String, dynamic>>> attributeList;
  final MapController mapController;
  final double maxzoom;
  final Function()? reloadFeatures;

  const SearchDialog({
    super.key,
    required this.dataCubit,
    required this.layerList,
    required this.attributeList,
    required this.mapController,
    required this.maxzoom,
    this.reloadFeatures,
  });

  @override
  SearchDialogState createState() => SearchDialogState();
}

class SearchDialogState extends State<SearchDialog> {
  String? selectedLayerId;
  String? selectedAttrId;
  String searchQuery = '';
  bool isDataReady = false;
  String? errorMessage;
  List<EcomiObject> searchResults = [];
  Map<String, EcomiObject> prefilteredMap = {};
  Timer? debounce;

  int pageSize = 10;
  ScrollController scrollController = ScrollController();
  final TextEditingController searchController = TextEditingController();

  @override
  void initState() {
    super.initState();
    searchController.addListener(() {
      if (searchController.text.isEmpty) {
        setState(() {
          searchQuery = '';
          searchResults = [];
        });
      }
    });
  }

  @override
  void dispose() {
    debounce?.cancel();
    super.dispose();
  }

  String normalizeKey(String input) {
    return input
        .toLowerCase()
        .replaceAll(RegExp(r'[^\w\s]'), '')
        .replaceAll(' ', '_');
  }

  Future<void> prefilterData() async {
    if (selectedLayerId == null || selectedAttrId == null) {
      prefilteredMap = {};
      return;
    }

    setState(() {
      isDataReady = false;
      errorMessage = null;
    });

    try {
      final layer = widget.layerList.firstWhere(
        (l) => l['layerId'] == selectedLayerId,
        orElse: () => {},
      );
      final geometryType = layer['geometryType'] as String?;
      String type =
          geometryType!.toLowerCase().contains('point')
              ? 'marker'
              : geometryType.toLowerCase().contains('linestring')
              ? 'polyline'
              : 'polygon';

      final rawResults = await _filterFeatures(
        widget.dataCubit,
        type,
        selectedLayerId!,
        selectedAttrId!,
        '',
      );

      final Map<String, EcomiObject> tempMap = {};

      for (var obj in rawResults) {
        final value = obj.attributes[selectedAttrId!]?.toString() ?? '';
        final key = normalizeKey(value);
        tempMap[key] = obj;
      }

      setState(() {
        prefilteredMap = tempMap;
        Future.delayed(const Duration(seconds: 2), () {
          setState(() {
            isDataReady = true;
          });
        });
      });
    } catch (e) {
      setState(() {
        isDataReady = false;
        errorMessage = 'Prefilter failed: $e';
      });
    }
  }

  void performSearch() {
    debounce?.cancel();
    debounce = Timer(const Duration(milliseconds: 300), () async {
      if (searchQuery.isEmpty || !isDataReady) {
        setState(() {
          searchResults = [];
          errorMessage = null;
        });
        return;
      }

      final String query = searchQuery.toLowerCase();
      final List<String> keys = prefilteredMap.keys.toList();

      final List<String> matchedKeys = await compute(_filterKeys, (
        keys,
        query,
      ));

      setState(() {
        searchResults = matchedKeys.map((key) => prefilteredMap[key]!).toList();
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    final mediaQuery = MediaQuery.of(context);
    final dialogWidth = mediaQuery.size.width * 0.8;
    final maxHeight = mediaQuery.size.height * 0.6;

    final layerItems =
        widget.layerList.map<DropdownMenuItem>((layer) {
          return DropdownMenuItem(
            value: layer['layerId'],
            child: Text(
              layer['name'] ?? 'Unnamed Layer',
              overflow: TextOverflow.ellipsis,
            ),
          );
        }).toList();

    return Scaffold(
      resizeToAvoidBottomInset: false,
      backgroundColor: Colors.transparent,
      body: Stack(
        children: [
          Positioned.fill(
            child: GestureDetector(
              onTap: Navigator.of(context).pop,
              behavior: HitTestBehavior.opaque,
            ),
          ),
          Positioned(
            top: 40,
            left: (mediaQuery.size.width - dialogWidth) / 2,
            child: Material(
              elevation: 8,
              borderRadius: BorderRadius.circular(16),
              color: Colors.grey.shade300,
              child: Container(
                width: dialogWidth,
                constraints: BoxConstraints(maxHeight: maxHeight),
                padding: const EdgeInsets.all(16),
                child: SingleChildScrollView(
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Search Feature',
                        style: TextStyle(
                          fontWeight: FontWeight.bold,
                          fontSize: 20,
                        ),
                      ),
                      const SizedBox(height: 16),
                      // Layer Dropdown
                      DropdownButtonFormField(
                        decoration: InputDecoration(
                          labelText: 'Select Layer',
                          filled: true,
                          fillColor: Colors.grey[50],
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(12),
                            borderSide: BorderSide(color: Colors.grey[300]!),
                          ),
                          contentPadding: EdgeInsets.symmetric(
                            horizontal: 16,
                            vertical: 12,
                          ),
                        ),
                        value: selectedLayerId,
                        items: layerItems,
                        onChanged: (value) {
                          setState(() {
                            selectedLayerId = value;
                            selectedAttrId = null;
                            searchQuery = '';
                            searchResults = [];
                            prefilteredMap = {};
                            isDataReady = false;
                            errorMessage = null;
                          });
                        },
                        isExpanded: true,
                      ),
                      const SizedBox(height: 16),
                      // Attribute Dropdown
                      DropdownButtonFormField(
                        decoration: InputDecoration(
                          labelText: 'Select Attribute',
                          enabled: selectedLayerId != null,
                          filled: true,
                          fillColor: Colors.grey[50],
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(12),
                            borderSide: BorderSide(color: Colors.grey[300]!),
                          ),
                          contentPadding: const EdgeInsets.symmetric(
                            horizontal: 16,
                            vertical: 12,
                          ),
                        ),
                        value: selectedAttrId,
                        items:
                            (widget.attributeList[selectedLayerId] ?? [])
                                .where((attr) {
                                  if (selectedLayerId == privateWell) {
                                    return attr['attrId'] == 'attr0' ||
                                        attr['attrId'] == 'attr1';
                                  }
                                  return true;
                                })
                                .map(
                                  (attr) => DropdownMenuItem(
                                    value: attr['attrId'].toString(),
                                    child: Text(attr['name'] ?? 'N/A'),
                                  ),
                                )
                                .toList(),
                        onChanged: (value) {
                          setState(() {
                            selectedAttrId = value;
                            searchQuery = '';
                            searchResults = [];
                            prefilteredMap = {};
                            isDataReady = false;
                            errorMessage = null;
                            pageSize = 10;
                          });
                          prefilterData();
                        },
                        isExpanded: true,
                      ),
                      const SizedBox(height: 16),
                      // Search TextField
                      TextField(
                        autofocus: true,
                        enabled: selectedAttrId != null,
                        controller: searchController,
                        decoration: InputDecoration(
                          labelText: 'Search',
                          hintText: 'Type to search...',
                          filled: true,
                          fillColor: Colors.grey[50],
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(12),
                            borderSide: BorderSide(color: Colors.grey[300]!),
                          ),
                          contentPadding: const EdgeInsets.symmetric(
                            horizontal: 16,
                            vertical: 12,
                          ),
                          suffixIcon:
                              searchController.text.isNotEmpty
                                  ? IconButton(
                                    icon: Icon(Icons.clear),
                                    onPressed: () {
                                      searchController.clear();
                                      setState(() {
                                        searchQuery = '';
                                        searchResults = [];
                                      });
                                    },
                                  )
                                  : null,
                        ),
                        onChanged: (value) {
                          setState(() {
                            searchQuery = normalizeKey(value);
                          });
                          performSearch();
                        },
                      ),
                      const SizedBox(height: 8),
                      // Search Results
                      SizedBox(
                        height: 200,
                        child: Visibility(
                          visible: searchResults.isNotEmpty,
                          child: ListView.builder(
                            itemCount: pageSize + 1,
                            itemBuilder: (context, index) {
                              if (index < pageSize &&
                                  index < searchResults.length) {
                                final feature = searchResults[index];
                                final displayText =
                                    (feature.layerId == privateWell &&
                                            selectedAttrId == 'attr0')
                                        ? (double.tryParse(
                                                  feature.attributes[selectedAttrId!] ??
                                                      '',
                                                ) ??
                                                0.0)
                                            .toInt()
                                            .toString()
                                        : feature.attributes[selectedAttrId!]
                                                ?.toString() ??
                                            'N/A';
                                return ListTile(
                                  tileColor: Colors.white70,
                                  title: Text(displayText),
                                  onTap: () async {
                                    await _moveMapToFeature(
                                      feature.multi,
                                      feature.geometry,
                                      widget.mapController,
                                      widget.maxzoom,
                                    );
                                    if (widget.reloadFeatures != null) {
                                      widget.reloadFeatures!();
                                    }
                                    Navigator.of(context).pop();
                                  },
                                );
                              } else {
                                return Padding(
                                  padding: const EdgeInsets.symmetric(
                                    vertical: 8.0,
                                  ),
                                  child: TextButton(
                                    onPressed: () {
                                      setState(() {
                                        pageSize += 10;
                                      });
                                    },
                                    child: const Text('Load More'),
                                  ),
                                );
                              }
                            },
                          ),
                        ),
                      ),
                      if (errorMessage != null)
                        Padding(
                          padding: const EdgeInsets.symmetric(vertical: 8.0),
                          child: Text(
                            errorMessage!,
                            style: TextStyle(
                              color: Theme.of(context).colorScheme.error,
                              fontSize: 14,
                            ),
                          ),
                        ),
                      // Action Buttons
                      Row(
                        mainAxisAlignment: MainAxisAlignment.end,
                        children: [
                          TextButton(
                            onPressed: Navigator.of(context).pop,
                            child: const Text('Cancel'),
                          ),
                          if (selectedAttrId != null)
                            ElevatedButton(
                              onPressed:
                                  isDataReady && searchQuery.isNotEmpty
                                      ? () async {
                                        final userInput =
                                            searchQuery.toLowerCase();
                                        final matches =
                                            searchResults.where((result) {
                                              final rawValue =
                                                  result
                                                      .attributes[selectedAttrId!] ??
                                                  '';
                                              final normalized =
                                                  normalizeSpecialCase(
                                                    result.layerId,
                                                    selectedAttrId!,
                                                    rawValue,
                                                  );
                                              return normalized.toLowerCase() ==
                                                  userInput;
                                            }).toList();
                                        if (matches.isNotEmpty &&
                                            matches.length == 1) {
                                          await _moveMapToFeature(
                                            matches[0].multi,
                                            matches[0].geometry,
                                            widget.mapController,
                                            widget.maxzoom,
                                          );
                                          Navigator.of(context).pop();
                                          return;
                                        }
                                        performSearch();
                                      }
                                      : null,
                              style: ElevatedButton.styleFrom(
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(12),
                                ),
                                padding: const EdgeInsets.symmetric(
                                  horizontal: 16,
                                ),
                              ),
                              child: const Text('Search'),
                            ),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Future<Iterable<dynamic>> _filterFeatures(
  DataCubit dataCubit,
  String type,
  String layerId,
  String attrId,
  String query,
) async {
  final String lowerQuery = query.toLowerCase();
  if (type == 'marker') {
    return dataCubit.markers.where(
      (obj) =>
          obj.layerId == layerId &&
          obj.attributes.containsKey(attrId) &&
          (obj.attributes[attrId]?.toString().toLowerCase() ?? '').contains(
            lowerQuery,
          ),
    );
  } else if (type == 'polyline') {
    return dataCubit.polylines.where(
      (obj) =>
          obj.layerId == layerId &&
          obj.attributes.containsKey(attrId) &&
          (obj.attributes[attrId]?.toString().toLowerCase() ?? '').contains(
            lowerQuery,
          ),
    );
  } else {
    return dataCubit.polygons.where(
      (obj) =>
          obj.layerId == layerId &&
          obj.attributes.containsKey(attrId) &&
          (obj.attributes[attrId]?.toString().toLowerCase() ?? '').contains(
            lowerQuery,
          ),
    );
  }
}

Future _moveMapToFeature(
  bool isMulti,
  String geometryWkt,
  MapController mapController,
  double maxzoom,
) async {
  try {
    List points = [];
    if (geometryWkt.toLowerCase().contains('point')) {
      if (isMulti) {
        points = multiPointWktToLatLng(geometryWkt);
      } else {
        points = [pointWktToLatLng(geometryWkt)];
      }
    } else if (geometryWkt.toLowerCase().contains('line')) {
      if (isMulti) {
        final latlists = multiLineWktToLatLng(geometryWkt);
        points = latlists[0];
      } else {
        points = lineWktToLatLng(geometryWkt);
      }
    } else if (geometryWkt.toLowerCase().contains('polygon')) {
      if (isMulti) {
        final latlists = multiPolygonWktToLatLng(geometryWkt);
        points = latlists[0];
      } else {
        points = polygonWktToLatLng(geometryWkt);
      }
    }
    if (points.isEmpty) {
      throw Exception('No valid points found in geometry');
    } else {
      mapController.move(points[0], maxzoom);
    }
  } catch (e) {
    debugPrint('isMulti: $isMulti');
    debugPrint('geometry: $geometryWkt');
    debugPrint("Failed to move to feature: $e");
    rethrow; // Re-throw to allow UI to handle the error
  }
}

String normalizeSpecialCase(String layerId, String attrId, String rawValue) {
  if (attrId == 'attr0') {
    final numValue = double.tryParse(rawValue);
    if (numValue != null) {
      return numValue.toInt().toString();
    }
  }
  return rawValue;
}