import 'dart:io';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:environment_monitoring_app/models/tarball_data.dart';
import 'package:environment_monitoring_app/models/in_situ_sampling_data.dart';
import 'package:environment_monitoring_app/services/local_storage_service.dart';
import 'package:environment_monitoring_app/services/marine_api_service.dart';

class SubmissionLogEntry {
  final String type; // e.g., 'Manual Sampling', 'Tarball Sampling'
  final String title;
  final String stationCode;
  final DateTime submissionDateTime;
  final String? reportId;
  final String status;
  final String message;
  final Map<String, dynamic> rawData;
  bool isResubmitting;

  SubmissionLogEntry({
    required this.type,
    required this.title,
    required this.stationCode,
    required this.submissionDateTime,
    this.reportId,
    required this.status,
    required this.message,
    required this.rawData,
    this.isResubmitting = false,
  });
}

class MarineManualDataStatusLog extends StatefulWidget {
  const MarineManualDataStatusLog({super.key});

  @override
  State<MarineManualDataStatusLog> createState() => _MarineManualDataStatusLogState();
}

class _MarineManualDataStatusLogState extends State<MarineManualDataStatusLog> {
  final LocalStorageService _localStorageService = LocalStorageService();
  final MarineApiService _marineApiService = MarineApiService();

  // Raw data lists
  List<SubmissionLogEntry> _manualLogs = [];
  List<SubmissionLogEntry> _tarballLogs = [];

  // Filtered lists for the UI
  List<SubmissionLogEntry> _filteredManualLogs = [];
  List<SubmissionLogEntry> _filteredTarballLogs = [];

  // Per-category search controllers
  final Map<String, TextEditingController> _searchControllers = {};

  bool _isLoading = true;
  final Map<String, bool> _isResubmitting = {};

  @override
  void initState() {
    super.initState();
    _searchControllers['Manual Sampling'] = TextEditingController()..addListener(_filterLogs);
    _searchControllers['Tarball Sampling'] = TextEditingController()..addListener(_filterLogs);
    _loadAllLogs();
  }

  @override
  void dispose() {
    _searchControllers['Manual Sampling']?.dispose();
    _searchControllers['Tarball Sampling']?.dispose();
    super.dispose();
  }

  Future<void> _loadAllLogs() async {
    setState(() => _isLoading = true);

    final tarballLogs = await _localStorageService.getAllTarballLogs();
    final inSituLogs = await _localStorageService.getAllInSituLogs();

    final List<SubmissionLogEntry> tempManual = [];
    final List<SubmissionLogEntry> tempTarball = [];

    // Map In-Situ logs to Manual Sampling
    for (var log in inSituLogs) {
      final String dateStr = log['data_capture_date'] ?? log['sampling_date'] ?? '';
      final String timeStr = log['data_capture_time'] ?? log['sampling_time'] ?? '';

      tempManual.add(SubmissionLogEntry(
        type: 'Manual Sampling',
        title: log['selectedStation']?['man_station_name'] ?? 'Unknown Station',
        stationCode: log['selectedStation']?['man_station_code'] ?? 'N/A',
        submissionDateTime: DateTime.tryParse('$dateStr $timeStr') ?? DateTime.now(),
        reportId: log['reportId']?.toString(),
        status: log['submissionStatus'] ?? 'L1',
        message: log['submissionMessage'] ?? 'No status message.',
        rawData: log,
      ));
    }

    // Map Tarball logs
    for (var log in tarballLogs) {
      tempTarball.add(SubmissionLogEntry(
        type: 'Tarball Sampling',
        title: log['selectedStation']?['tbl_station_name'] ?? 'Unknown Station',
        stationCode: log['selectedStation']?['tbl_station_code'] ?? 'N/A',
        submissionDateTime: DateTime.tryParse('${log['sampling_date']} ${log['sampling_time']}') ?? DateTime.now(),
        reportId: log['reportId']?.toString(),
        status: log['submissionStatus'] ?? 'L1',
        message: log['submissionMessage'] ?? 'No status message.',
        rawData: log,
      ));
    }

    tempManual.sort((a, b) => b.submissionDateTime.compareTo(a.submissionDateTime));
    tempTarball.sort((a, b) => b.submissionDateTime.compareTo(a.submissionDateTime));

    if (mounted) {
      setState(() {
        _manualLogs = tempManual;
        _tarballLogs = tempTarball;
        _isLoading = false;
      });
      _filterLogs(); // Perform initial filter
    }
  }

  void _filterLogs() {
    final manualQuery = _searchControllers['Manual Sampling']?.text.toLowerCase() ?? '';
    final tarballQuery = _searchControllers['Tarball Sampling']?.text.toLowerCase() ?? '';

    setState(() {
      _filteredManualLogs = _manualLogs.where((log) => _logMatchesQuery(log, manualQuery)).toList();
      _filteredTarballLogs = _tarballLogs.where((log) => _logMatchesQuery(log, tarballQuery)).toList();
    });
  }

  bool _logMatchesQuery(SubmissionLogEntry log, String query) {
    if (query.isEmpty) return true;
    return log.title.toLowerCase().contains(query) ||
        log.stationCode.toLowerCase().contains(query) ||
        (log.reportId?.toLowerCase() ?? '').contains(query);
  }

  Future<void> _resubmitData(SubmissionLogEntry log) async {
    final logKey = log.reportId ?? log.submissionDateTime.toIso8601String();
    if (mounted) {
      setState(() {
        _isResubmitting[logKey] = true;
      });
    }

    try {
      final result = await _performResubmission(log);
      final logData = log.rawData;

      logData['submissionStatus'] = result['status'];
      logData['submissionMessage'] = result['message'];
      logData['reportId'] = result['reportId']?.toString() ?? logData['reportId'];

      if (log.type == 'Manual Sampling') {
        await _localStorageService.updateInSituLog(logData);
      } else if (log.type == 'Tarball Sampling') {
        await _localStorageService.updateTarballLog(logData);
      }

      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Resubmission successful!')),
        );
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Resubmission failed: $e')),
        );
      }
    } finally {
      if (mounted) {
        setState(() {
          _isResubmitting.remove(logKey);
        });
        await _loadAllLogs();
      }
    }
  }

  Future<Map<String, dynamic>> _performResubmission(SubmissionLogEntry log) async {
    final logData = log.rawData;

    if (log.type == 'Manual Sampling') {
      final InSituSamplingData dataToResubmit = InSituSamplingData()
        ..firstSamplerUserId = int.tryParse(logData['first_sampler_user_id']?.toString() ?? '')
        ..secondSampler = logData['secondSampler']
        ..samplingDate = logData['sampling_date']
        ..samplingTime = logData['sampling_time']
        ..samplingType = logData['sampling_type']
        ..sampleIdCode = logData['sample_id_code']
        ..selectedStation = logData['selectedStation']
        ..currentLatitude = logData['current_latitude']?.toString()
        ..currentLongitude = logData['current_longitude']?.toString()
        ..distanceDifferenceInKm = double.tryParse(logData['distance_difference']?.toString() ?? '0.0')
        ..weather = logData['weather']
        ..tideLevel = logData['tide_level']
        ..seaCondition = logData['sea_condition']
        ..eventRemarks = logData['event_remarks']
        ..labRemarks = logData['lab_remarks']
        ..optionalRemark1 = logData['optional_photo_remark_1']
        ..optionalRemark2 = logData['optional_photo_remark_2']
        ..optionalRemark3 = logData['optional_photo_remark_3']
        ..optionalRemark4 = logData['optional_photo_remark_4']
        ..sondeId = logData['sonde_id']
        ..dataCaptureDate = logData['data_capture_date']
        ..dataCaptureTime = logData['data_capture_time']
        ..oxygenConcentration = double.tryParse(logData['oxygen_concentration_mg_l']?.toString() ?? '0.0')
        ..oxygenSaturation = double.tryParse(logData['oxygen_saturation_percent']?.toString() ?? '0.0')
        ..ph = double.tryParse(logData['ph']?.toString() ?? '0.0')
        ..salinity = double.tryParse(logData['salinity_ppt']?.toString() ?? '0.0')
        ..electricalConductivity = double.tryParse(logData['ec_us_cm']?.toString() ?? '0.0')
        ..temperature = double.tryParse(logData['temperature_c']?.toString() ?? '0.0')
        ..tds = double.tryParse(logData['tds_mg_l']?.toString() ?? '0.0')
        ..turbidity = double.tryParse(logData['turbidity_ntu']?.toString() ?? '0.0')
        ..tss = double.tryParse(logData['tss_mg_l']?.toString() ?? '0.0')
        ..batteryVoltage = double.tryParse(logData['battery_v']?.toString() ?? '0.0');

      final Map<String, File?> imageFiles = {};
      final imageKeys = dataToResubmit.toApiImageFiles().keys;
      for (var key in imageKeys) {
        final imagePath = logData[key];
        if (imagePath is String && imagePath.isNotEmpty) {
          final file = File(imagePath);
          if (await file.exists()) {
            imageFiles[key] = file;
          }
        }
      }

      return _marineApiService.submitInSituSample(
        formData: dataToResubmit.toApiFormData(),
        imageFiles: imageFiles,
      );
    } else if (log.type == 'Tarball Sampling') {
      final int? firstSamplerId = int.tryParse(logData['first_sampler_user_id']?.toString() ?? '');
      final int? classificationId = int.tryParse(logData['classification_id']?.toString() ?? '');

      final TarballSamplingData dataToResubmit = TarballSamplingData()
        ..selectedStation = logData['selectedStation']
        ..samplingDate = logData['sampling_date']
        ..samplingTime = logData['sampling_time']
        ..firstSamplerUserId = firstSamplerId
        ..secondSampler = logData['secondSampler']
        ..classificationId = classificationId
        ..currentLatitude = logData['current_latitude']?.toString()
        ..currentLongitude = logData['current_longitude']?.toString()
        ..distanceDifference = logData['distance_difference']
        ..optionalRemark1 = logData['optional_photo_remark_01']
        ..optionalRemark2 = logData['optional_photo_remark_02']
        ..optionalRemark3 = logData['optional_photo_remark_03']
        ..optionalRemark4 = logData['optional_photo_remark_04'];

      final Map<String, File?> imageFiles = {};
      final imageKeys = ['left_side_coastal_view', 'right_side_coastal_view', 'drawing_vertical_lines', 'drawing_horizontal_line', 'optional_photo_01', 'optional_photo_02', 'optional_photo_03', 'optional_photo_04'];
      for (var key in imageKeys) {
        final imagePath = logData[key];
        if (imagePath != null && imagePath.isNotEmpty) {
          final file = File(imagePath);
          if (await file.exists()) imageFiles[key] = file;
        }
      }

      return _marineApiService.submitTarballSample(formData: dataToResubmit.toFormData(), imageFiles: imageFiles);
    }

    throw Exception('Unknown submission type: ${log.type}');
  }

  @override
  Widget build(BuildContext context) {
    final hasAnyLogs = _manualLogs.isNotEmpty || _tarballLogs.isNotEmpty;
    final hasFilteredLogs = _filteredManualLogs.isNotEmpty || _filteredTarballLogs.isNotEmpty;

    final logCategories = {
      'Manual Sampling': _filteredManualLogs,
      'Tarball Sampling': _filteredTarballLogs,
    };

    return Scaffold(
      appBar: AppBar(title: const Text('Marine Data Status Log')),
      body: _isLoading
          ? const Center(child: CircularProgressIndicator())
          : RefreshIndicator(
        onRefresh: _loadAllLogs,
        child: !hasAnyLogs
            ? const Center(child: Text('No submission logs found.'))
            : ListView(
          padding: const EdgeInsets.all(8.0),
          children: [
            ...logCategories.entries
                .where((entry) => entry.value.isNotEmpty)
                .map((entry) => _buildCategorySection(entry.key, entry.value)),
            if (!hasFilteredLogs && hasAnyLogs)
              const Center(
                child: Padding(
                  padding: EdgeInsets.all(24.0),
                  child: Text('No logs match your search.'),
                ),
              )
          ],
        ),
      ),
    );
  }

  Widget _buildCategorySection(String category, List<SubmissionLogEntry> logs) {
    final listHeight = (logs.length > 5 ? 5.5 : logs.length.toDouble()) * 75.0;

    return Card(
      margin: const EdgeInsets.symmetric(vertical: 8.0),
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(category, style: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold)),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 8.0),
              child: TextField(
                controller: _searchControllers[category],
                decoration: InputDecoration(
                  hintText: 'Search in $category...',
                  prefixIcon: const Icon(Icons.search, size: 20),
                  isDense: true,
                  border: const OutlineInputBorder(),
                ),
              ),
            ),
            const Divider(),
            logs.isEmpty
                ? const Padding(
                padding: EdgeInsets.all(16.0),
                child: Center(child: Text('No logs match your search in this category.')))
                : ConstrainedBox(
              constraints: BoxConstraints(maxHeight: listHeight),
              child: ListView.builder(
                shrinkWrap: true,
                itemCount: logs.length,
                itemBuilder: (context, index) {
                  return _buildLogListItem(logs[index]);
                },
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildLogListItem(SubmissionLogEntry log) {
    final isFailed = log.status != 'L3';
    final logKey = log.reportId ?? log.submissionDateTime.toIso8601String();
    final isResubmitting = _isResubmitting[logKey] ?? false;
    final title = '${log.title} (${log.stationCode})';
    final subtitle = DateFormat('yyyy-MM-dd HH:mm').format(log.submissionDateTime);

    return ExpansionTile(
      leading: Icon(
        isFailed ? Icons.error_outline : Icons.check_circle_outline,
        color: isFailed ? Colors.red : Colors.green,
      ),
      title: Text(title, style: const TextStyle(fontWeight: FontWeight.w500)),
      subtitle: Text(subtitle),
      trailing: isFailed
          ? (isResubmitting
          ? const SizedBox(height: 24, width: 24, child: CircularProgressIndicator(strokeWidth: 3))
          : IconButton(icon: const Icon(Icons.sync, color: Colors.blue), tooltip: 'Resubmit', onPressed: () => _resubmitData(log)))
          : null,
      children: [
        Padding(
          padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _buildDetailRow('Report ID:', log.reportId ?? 'N/A'),
              _buildDetailRow('Status:', log.message),
              _buildDetailRow('Submission Type:', log.type),
            ],
          ),
        )
      ],
    );
  }

  Widget _buildDetailRow(String label, String value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 2.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('$label ', style: const TextStyle(fontWeight: FontWeight.bold)),
          Expanded(child: Text(value)),
        ],
      ),
    );
  }
}