import 'dart:convert';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../models/cycle_entry.dart';
import '../models/teaching_plan.dart';
import '../models/prayer_request.dart';

class SyncService {
  // Use 192.168.1.81 for the user's specific setup as they are testing across devices.
  // In a real app we'd allow this to be configured.
  // static const String _baseUrl = 'http://localhost:8090';

  // Dynamic Base URL
  static String get _baseUrl {
    if (kIsWeb) {
      // On web, use the current window's hostname (whether localhost or IP)
      // and target port 8090.
      final host = Uri.base.host;
      // If host is empty (some web views), fallback.
      if (host.isNotEmpty) {
        return 'http://$host:8090';
      }
    }
    // Mobile / Desktop App Fallback
    // Use the specific local IP for this user's physical device testing.
    return 'http://192.168.1.81:8090';
  }

  // Preview Partner Link (Check without linking)
  Future<Map<String, dynamic>> previewPartnerId(String targetId) async {
    try {
      final url = Uri.parse('$_baseUrl/sync/preview');
      final response = await http.post(
        url,
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({
          'targetId': targetId,
        }),
      );

      if (response.statusCode == 200) {
        return jsonDecode(response.body);
      } else {
        throw Exception('Failed to preview: ${response.body}');
      }
    } catch (e) {
      debugPrint('Preview Error: $e');
      rethrow;
    }
  }

  // Link Partner
  Future<Map<String, dynamic>> verifyPartnerId(
      String userId, String targetId) async {
    try {
      final url = Uri.parse('$_baseUrl/sync/link');
      final response = await http.post(
        url,
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({
          'userId': userId,
          'targetId': targetId,
        }),
      );

      if (response.statusCode == 200) {
        return jsonDecode(response.body);
      } else {
        throw Exception('Failed to link: ${response.body}');
      }
    } catch (e) {
      debugPrint('Link Error: $e');
      rethrow;
    }
  }

  // Push data to backend
  Future<void> pushSyncData({
    required String userId,
    required List<CycleEntry> entries,
    required List<TeachingPlan> teachingPlans,
    required List<PrayerRequest> prayerRequests,
    Map<String, dynamic>? userDetails,
  }) async {
    try {
      final url = Uri.parse('$_baseUrl/sync/push');
      final payload = {
        'userId': userId,
        'entries': entries.map((e) => _cycleEntryToJson(e)).toList(),
        'teachingPlans':
            teachingPlans.map((p) => _teachingPlanToJson(p)).toList(),
        'prayerRequests':
            prayerRequests.map((r) => _prayerRequestToJson(r)).toList(),
        if (userDetails != null) 'userDetails': userDetails,
      };

      final response = await http.post(
        url,
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode(payload),
      );

      if (response.statusCode == 200) {
        debugPrint('Sync Push Successful');
      } else {
        debugPrint('Sync Push Failed: ${response.body}');
      }
    } catch (e) {
      debugPrint('Sync Push Error: $e');
    }
  }

  // Pull data from backend
  Future<Map<String, dynamic>> pullSyncData(String userId,
      {String? partnerId}) async {
    try {
      var urlStr = '$_baseUrl/sync/pull?userId=$userId';
      if (partnerId != null && partnerId.isNotEmpty) {
        urlStr += '&partnerId=$partnerId';
      }

      final url = Uri.parse(urlStr);
      final response = await http.get(url);

      if (response.statusCode == 200) {
        final data = jsonDecode(response.body);

        // entries
        final List entriesJson = data['entries'] ?? [];
        final entries =
            entriesJson.map((json) => _jsonToCycleEntry(json)).toList();

        // teaching plans
        final List plansJson = data['teachingPlans'] ?? [];
        final plans =
            plansJson.map((json) => _jsonToTeachingPlan(json)).toList();

        // prayer requests
        final List prayersJson = data['prayerRequests'] ?? [];
        final prayers =
            prayersJson.map((json) => _jsonToPrayerRequest(json)).toList();

        return {
          'entries': entries,
          'teachingPlans': plans,
          'prayerRequests': prayers,
          if (data['userProfile'] != null)
            'userProfile': data['userProfile'] as Map<String, dynamic>,
        };
      }
    } catch (e) {
      debugPrint('Sync Pull Error: $e');
    }
    return {
      'entries': <CycleEntry>[],
      'teachingPlans': <TeachingPlan>[],
      'prayerRequests': <PrayerRequest>[],
    };
  }

  // --- Adapters ---

  Map<String, dynamic> _cycleEntryToJson(CycleEntry entry) {
    // Convert boolean symptoms to list of strings
    final symptomsList = <String>[];
    if (entry.hasHeadache) symptomsList.add('headache');
    if (entry.hasBloating) symptomsList.add('bloating');
    if (entry.hasBreastTenderness) symptomsList.add('breastTenderness');
    if (entry.hasFatigue) symptomsList.add('fatigue');
    if (entry.hasAcne) symptomsList.add('acne');
    if (entry.hasLowerBackPain) symptomsList.add('lowerBackPain');
    if (entry.hasConstipation) symptomsList.add('constipation');
    if (entry.hasDiarrhea) symptomsList.add('diarrhea');
    if (entry.hasInsomnia) symptomsList.add('insomnia');

    return {
      'id': entry.id,
      'date': entry.date.toIso8601String(),
      'flowIntensity': entry.flowIntensity?.name,
      'isPeriodDay': entry.isPeriodDay,
      'symptoms': jsonEncode(symptomsList),
      'moods': jsonEncode(entry.mood != null ? [entry.mood!.name] : []),
      'notes': entry.notes,
      'createdAt': entry.createdAt.toIso8601String(),
      'updatedAt': entry.updatedAt.toIso8601String(),
    };
  }

  CycleEntry _jsonToCycleEntry(Map<String, dynamic> json) {
    // FlowIntensity enum parsing
    FlowIntensity? flow;
    if (json['flowIntensity'] != null) {
      flow = FlowIntensity.values.firstWhere(
        (e) => e.name == json['flowIntensity'],
        orElse: () => FlowIntensity.medium,
      );
    }

    // Mood parsing
    MoodLevel? mood;
    final moodsList = _parseList(json['moods']);
    if (moodsList.isNotEmpty) {
      try {
        mood = MoodLevel.values.firstWhere((e) => e.name == moodsList.first);
      } catch (_) {}
    }

    final symptoms = _parseList(json['symptoms']);

    return CycleEntry(
      id: json['id'],
      date: DateTime.parse(json['date']),
      flowIntensity: flow,
      isPeriodDay: json['isPeriodDay'] == true,
      mood: mood,
      hasHeadache: symptoms.contains('headache'),
      hasBloating: symptoms.contains('bloating'),
      hasBreastTenderness: symptoms.contains('breastTenderness'),
      hasFatigue: symptoms.contains('fatigue'),
      hasAcne: symptoms.contains('acne'),
      hasLowerBackPain: symptoms.contains('lowerBackPain'),
      hasConstipation: symptoms.contains('constipation'),
      hasDiarrhea: symptoms.contains('diarrhea'),
      hasInsomnia: symptoms.contains('insomnia'),
      notes: json['notes'],
      createdAt: json['createdAt'] != null
          ? DateTime.parse(json['createdAt'])
          : DateTime.now(),
      updatedAt: json['updatedAt'] != null
          ? DateTime.parse(json['updatedAt'])
          : DateTime.now(),
    );
  }

  // Teaching Plan
  Map<String, dynamic> _teachingPlanToJson(TeachingPlan plan) {
    return {
      'id': plan.id,
      'date': plan.date.toIso8601String(),
      'topic': plan.topic,
      'scriptureReference': plan.scriptureReference,
      'notes': plan.notes,
      'isCompleted': plan.isCompleted,
    };
  }

  TeachingPlan _jsonToTeachingPlan(Map<String, dynamic> json) {
    return TeachingPlan(
      id: json['id'],
      date: DateTime.parse(json['date']),
      topic: json['topic'],
      scriptureReference: json['scriptureReference'],
      notes: json['notes'],
      isCompleted: json['isCompleted'] == true,
    );
  }

  // Prayer Request
  Map<String, dynamic> _prayerRequestToJson(PrayerRequest request) {
    return {
      'id': request.id,
      'request': request.request,
      'isAnswered': request.isAnswered,
      'createdAt': request.createdAt.toIso8601String(),
      'updatedAt': request.updatedAt.toIso8601String(),
    };
  }

  PrayerRequest _jsonToPrayerRequest(Map<String, dynamic> json) {
    return PrayerRequest(
      id: json['id'],
      request: json['request'],
      isAnswered: json['isAnswered'] == true,
      createdAt: DateTime.parse(json['createdAt']),
      updatedAt: DateTime.parse(json['updatedAt']),
    );
  }

  List<String> _parseList(dynamic jsonVal) {
    if (jsonVal == null) return [];
    if (jsonVal is String) {
      try {
        return List<String>.from(jsonDecode(jsonVal));
      } catch (_) {
        return [];
      }
    }
    return List<String>.from(jsonVal);
  }
}
