import 'dart:async';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:get/get.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

import 'app_database.dart';

enum SyncStatus { idle, syncing, error }

class SyncService extends GetxService {
  static SyncService get to => Get.find();

  final syncStatus = SyncStatus.idle.obs;
  final pendingCount = 0.obs;

  StreamSubscription? _connectivitySub;
  final _supabase = Supabase.instance.client;

  // AppDatabase — nincs külön DB fájl
  AppDatabase get _db => AppDatabase.instance;

  @override
  Future<void> onInit() async {
    super.onInit();
    await _updatePendingCount();
    _startConnectivityListener();

    if (await _hasConnectivity()) {
      unawaited(_syncPendingItems());
    }
  }

  @override
  Future<void> onClose() async {
    await _connectivitySub?.cancel();
    super.onClose();
  }

  // ── Publikus API ──────────────────────────────────────────────────

  Future<void> saveMeasuredPoint(Map<String, dynamic> point) async {
    final projectId = point['projectId'] as int?;
    final isLocalOnly = await _isLocalOnlyProject(projectId);

    final localId = await _db.insertPendingPoint(point);

    if (isLocalOnly) {
      await _db.markPointSynced(localId);
      return;
    }
    await _updatePendingCount();

    if (await _hasConnectivity()) {
      await _syncSinglePoint(localId, point);
    }
  }

  // ── Szinkronizálás ────────────────────────────────────────────────

  Future<void> _syncSinglePoint(int localId, Map<String, dynamic> point) async {
    try {
      await _supabase.from('TerepiSeged_MeasuredPoints').insert(point);

      await _supabase
          .from('TerepiSeged_Receiver')
          .update({'isMeasured': true}).eq('pointNumber', point['pointNumber']);

      await _db.markPointSynced(localId);
      await _updatePendingCount();
    } catch (_) {
      await _db.markPointError(localId);
    }
  }

  Future<void> _syncPendingItems() async {
    if (syncStatus.value == SyncStatus.syncing) return;

    final pending = await _db.getPendingPoints();
    if (pending.isEmpty) return;

    syncStatus.value = SyncStatus.syncing;

    for (final row in pending) {
      final localId = row['id'] as int;
      try {
        final supaPoint = {
          'pointNumber': row['point_number'],
          'gnssNumber': row['gnss_number'],
          'latitude': row['latitude'],
          'longitude': row['longitude'],
          'altitude': row['altitude'],
          'heightOfGeoid': row['height_of_geoid'],
          'eovX': row['eov_x'],
          'eovY': row['eov_y'],
          'poleHeight': row['pole_height'],
          'horizontalError': row['horizontal_error'],
          'verticalError': row['vertical_error'],
          'description': row['description'],
          'isDeleted': row['is_deleted'] == 1,
          'projectId': row['project_id'],
        };

        await _supabase.from('TerepiSeged_MeasuredPoints').insert(supaPoint);

        await _supabase.from('TerepiSeged_Receiver').update(
            {'isMeasured': true}).eq('pointNumber', row['point_number']);

        await _db.markPointSynced(localId);
      } catch (_) {
        // Következő alkalomra halaszt
      }
    }

    await _updatePendingCount();
    syncStatus.value = SyncStatus.idle;
    await _db.purgeSyncedPoints();
  }

  // ── Segédek ───────────────────────────────────────────────────────

  Future<void> _updatePendingCount() async {
    pendingCount.value = await _db.getPendingCount();
  }

  void _startConnectivityListener() {
    _connectivitySub = Connectivity()
        .onConnectivityChanged
        .listen((List<ConnectivityResult> results) async {
      final hasNet = results.any((r) => r != ConnectivityResult.none);
      if (hasNet && pendingCount.value > 0) {
        await _syncPendingItems();
      }
    });
  }

  Future<bool> _hasConnectivity() async {
    final results = await Connectivity().checkConnectivity();
    return results.any((r) => r != ConnectivityResult.none);
  }

  Future<bool> _isLocalOnlyProject(int? projectId) async {
    if (projectId == null) return false;
    final db = await AppDatabase.instance.database;
    final rows = await db.query(
      'projects',
      columns: ['is_local_only'],
      where: 'id = ?',
      whereArgs: [projectId],
      limit: 1,
    );
    if (rows.isEmpty) return false;
    return (rows.first['is_local_only'] as int?) == 1;
  }
}
