import 'package:dio/dio.dart';
import '../models/sensor_model.dart';
import '../core/api_config.dart';
import 'iot_service.dart';

/// Implementasi [IotService] yang berkomunikasi ke Backend Express melalui REST API.
/// Menangani pemrosesan data mentah sensor, pemfilteran nilai kosong (null), serta riwayat grafik.
class ApiIotService implements IotService {
  final Dio _dio;
  final String deviceId;

  ApiIotService(this.deviceId, [Dio? dio]) : _dio = dio ?? Dio();

  @override
  Future<SensorModel> fetchSensorData() async {
    try {
      // Ambil 30 data riwayat terbaru dari backend.
      // Hal ini dilakukan agar kita bisa memfilter dan melewati data log yang nilainya null (misalnya log perubahan relay saja).
      final response = await _dio.get('${ApiConfig.baseUrl}/history/$deviceId?limit=30');
      if (response.statusCode == 200) {
        final List<dynamic> data = response.data;
        if (data.isEmpty) {
          return SensorModel(temperature: 0, humidity: 0, timestamp: DateTime.now());
        }

        final firstItem = data.first;
        
        // Mencari entri pertama yang memiliki nilai sensor (suhu & kelembapan) yang valid (bukan null)
        final validItem = data.firstWhere(
          (item) => item['temperature'] != null && item['humidity'] != null,
          orElse: () => null,
        );
        
        if (validItem != null) {
          return SensorModel(
            temperature: (validItem['temperature'] as num).toDouble(),
            humidity: (validItem['humidity'] as num).toDouble(),
            relayOn: firstItem['relay_state'] as bool? ?? false,
            mode: firstItem['mode'] as String? ?? 'auto',
            timestamp: DateTime.parse(firstItem['created_at']).toLocal(),
          );
        } else {
          // Jika belum ada data sensor yang valid, kembalikan nilai placeholder (0) namun status relay & mode tetap valid
          return SensorModel(
            temperature: 0, 
            humidity: 0, 
            relayOn: firstItem['relay_state'] as bool? ?? false,
            mode: firstItem['mode'] as String? ?? 'auto',
            timestamp: DateTime.parse(firstItem['created_at']).toLocal()
          );
        }
      } else {
        throw Exception('Failed to fetch sensor data: ${response.statusCode}');
      }
    } catch (e) {
      throw Exception('Error fetching data: $e');
    }
  }

  /// Mengambil data histori sensor secara lengkap untuk kebutuhan pembuatan grafik real-time.
  /// [limit] menentukan jumlah maksimal entri data yang diambil.
  Future<List<SensorModel>> fetchHistory({int limit = 100}) async {
    try {
      final response = await _dio.get('${ApiConfig.baseUrl}/history/$deviceId?limit=$limit');
      if (response.statusCode == 200) {
        final List<dynamic> data = response.data;
        
        // Data dari API diurutkan DESC (terbaru di atas),
        // kita balik urutannya (reverse) agar berurutan ASC (terlama ke terbaru) untuk penggambaran grafik.
        // Lewati entri yang nilai suhu/kelembapannya null.
        final validData = data.where(
          (item) => item['temperature'] != null && item['humidity'] != null,
        ).toList();
        
        return validData.reversed.map((item) => SensorModel(
          temperature: (item['temperature'] as num).toDouble(),
          humidity: (item['humidity'] as num).toDouble(),
          relayOn: item['relay_state'] as bool? ?? false,
          mode: item['mode'] as String? ?? 'auto',
          timestamp: DateTime.parse(item['created_at']).toLocal(),
        )).toList();
      } else {
        throw Exception('Failed to fetch history: ${response.statusCode}');
      }
    } catch (e) {
      throw Exception('Error fetching history: $e');
    }
  }

  /// Mengambil riwayat data agregasi harian (rata-rata harian) untuk grafik bulanan.
  /// [days] menentukan berapa hari data ke belakang yang akan diambil.
  Future<List<Map<String, dynamic>>> fetchDailyHistory({int days = 30}) async {
    try {
      final response = await _dio.get('${ApiConfig.baseUrl}/history/$deviceId/daily?days=$days');
      if (response.statusCode == 200) {
        final List<dynamic> data = response.data;
        return data.cast<Map<String, dynamic>>();
      } else {
        throw Exception('Failed to fetch daily history: ${response.statusCode}');
      }
    } catch (e) {
      throw Exception('Error fetching daily history: $e');
    }
  }

  /// Mengambil riwayat data agregasi per jam (rata-rata per jam) untuk grafik harian.
  /// [days] menentukan rentang hari ke belakang data yang akan diambil.
  Future<List<Map<String, dynamic>>> fetchHourlyHistory({int days = 7}) async {
    try {
      final response = await _dio.get('${ApiConfig.baseUrl}/history/$deviceId/hourly?days=$days');
      if (response.statusCode == 200) {
        final List<dynamic> data = response.data;
        return data.cast<Map<String, dynamic>>();
      } else {
        throw Exception('Failed to fetch hourly history: ${response.statusCode}');
      }
    } catch (e) {
      throw Exception('Error fetching hourly history: $e');
    }
  }

  /// Mengambil status keaktifan perangkat (is_online, last_seen) dari backend.
  Future<Map<String, dynamic>> fetchDeviceStatus() async {
    try {
      final response = await _dio.get('${ApiConfig.baseUrl}/device/status/$deviceId');
      if (response.statusCode == 200) {
        return response.data as Map<String, dynamic>;
      } else {
        throw Exception('Failed to fetch device status: ${response.statusCode}');
      }
    } catch (e) {
      throw Exception('Error fetching device status: $e');
    }
  }
}
