import 'package:flutter/material.dart';

// ── Model: WateringSchedule ────────────────────────────────────
/// Model data untuk jadwal penyiraman otomatis yang tersimpan di sistem.
class WateringSchedule {
  /// ID unik jadwal yang digenerate oleh database.
  final String id;
  
  /// Jam penyiraman (WIB).
  final TimeOfDay time;
  
  /// Teks deskripsi pengulangan jadwal (misal: "Setiap Hari" atau "Sen, Rab, Jum").
  final String repeat;
  
  /// Menandakan apakah jadwal ini sedang aktif atau dinonaktifkan oleh pengguna.
  final bool isEnabled;
  
  /// Format string Cron asli yang disimpan di database (dalam zona waktu UTC).
  final String? cron;
  
  /// Durasi penyiraman dalam satuan detik. Default: 30 detik.
  final int durationS;

  const WateringSchedule({
    required this.id,
    required this.time,
    this.repeat = 'Setiap Hari',
    this.isEnabled = true,
    this.cron,
    this.durationS = 30,
  });

  /// Mengembalikan format jam dalam string 'HH.MM' untuk kebutuhan UI.
  String get formattedTime {
    final h = time.hour.toString().padLeft(2, '0');
    final m = time.minute.toString().padLeft(2, '0');
    return '$h.$m';
  }

  /// Menggandakan objek [WateringSchedule] dengan nilai baru secara immutable.
  WateringSchedule copyWith({
    String?    id,
    TimeOfDay? time,
    String?    repeat,
    bool?      isEnabled,
    String?    cron,
    int?       durationS,
  }) {
    return WateringSchedule(
      id: id ?? this.id,
      time: time ?? this.time,
      repeat: repeat ?? this.repeat,
      isEnabled: isEnabled ?? this.isEnabled,
      cron: cron ?? this.cron,
      durationS: durationS ?? this.durationS,
    );
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      (other is WateringSchedule &&
          runtimeType == other.runtimeType &&
          id == other.id);

  @override
  int get hashCode => id.hashCode;
}

// ── Enum: DeviceMode ─────────────────────────────────────────────────
/// Mode operasional dari modul IoT penyiram jamur:
/// - [auto_] : Pompa menyala otomatis jika sensor mendeteksi nilai melewati threshold atau sesuai jadwal.
/// - [manual] : Pompa hanya menyala saat dikendalikan langsung oleh pengguna dari aplikasi.
/// - [offline] : Status perangkat sedang tidak terhubung ke jaringan internet.
enum DeviceMode { auto_, manual, offline }

/// Ekstensi pendukung untuk mempermudah manipulasi nilai enum [DeviceMode].
extension DeviceModeX on DeviceMode {
  /// Nilai string yang digunakan dalam pertukaran data API dengan backend.
  String get apiValue {
    switch (this) {
      case DeviceMode.auto_:   return 'auto';
      case DeviceMode.manual:  return 'manual';
      case DeviceMode.offline: return 'offline';
    }
  }

  /// Teks berformat rapi untuk ditampilkan di UI label status.
  String get label {
    switch (this) {
      case DeviceMode.auto_:   return 'AUTO';
      case DeviceMode.manual:  return 'MANUAL';
      case DeviceMode.offline: return 'OFFLINE';
    }
  }

  /// Memparsing string dari backend menjadi tipe [DeviceMode].
  static DeviceMode fromString(String s) {
    final str = s.toLowerCase();
    if (str.startsWith('manual')) {
      return DeviceMode.manual;
    } else if (str.startsWith('offline')) {
      return DeviceMode.offline;
    } else {
      return DeviceMode.auto_;
    }
  }
}

// ── State: ControlState ────────────────────────────────────────────
/// State yang menampung seluruh konfigurasi kendali modul IoT (Pompa/Watering).
class ControlState {
  /// Status loading pemuatan data konfigurasi dari API.
  final bool isLoading;
  
  /// Status relay pompa saat ini (true = menyala, false = mati).
  final bool isPumpOn;
  
  /// Nilai threshold suhu minimal (°C).
  final double suhuMinLimit;

  /// Nilai threshold suhu maksimal (°C).
  final double suhuMaxLimit;
  
  /// Nilai threshold kelembapan minimal (%).
  final double kelembapanLimit;
  
  /// Daftar jadwal penyiraman otomatis yang telah diatur pengguna.
  final List<WateringSchedule> schedules;
  
  /// Pesan error dari server (jika ada).
  final String? errorMessage;
  
  /// Pesan sukses aksi (jika ada).
  final String? successMessage;
  
  /// Berapa lama pompa manual diset menyala (detik).
  final int? activePumpDuration;
  
  /// Timestamp waktu ketika pompa dinyalakan (untuk kalkulasi countdown sisa durasi).
  final DateTime? pumpTurnedOnAt;
  
  /// Mode alat saat ini (Auto / Manual / Offline).
  final DeviceMode deviceMode;
  
  /// Status loading khusus saat mengubah mode alat.
  final bool isModeLoading;

  const ControlState({
    this.isLoading = false,
    this.isPumpOn = false,
    this.suhuMinLimit = 22,
    this.suhuMaxLimit = 30,
    this.kelembapanLimit = 75,
    this.schedules = const [],
    this.errorMessage,
    this.successMessage,
    this.activePumpDuration,
    this.pumpTurnedOnAt,
    this.deviceMode = DeviceMode.auto_,
    this.isModeLoading = false,
  });

  /// State awal saat pertama kali dimuat di memori.
  factory ControlState.initial() => const ControlState(
    isLoading: true, // Data sedang dimuat dari API pada awal jalannya screen
    schedules: [],
  );

  /// Menggandakan [ControlState] secara immutable.
  /// Menyediakan fitur pembersihan pesan sukses/error atau countdown timer.
  ControlState copyWith({
    bool?   isLoading,
    bool?   isPumpOn,
    double? suhuMinLimit,
    double? suhuMaxLimit,
    double? kelembapanLimit,
    List<WateringSchedule>? schedules,
    String? errorMessage,
    String? successMessage,
    int? activePumpDuration,
    DateTime? pumpTurnedOnAt,
    DeviceMode? deviceMode,
    bool? isModeLoading,
    bool clearError = false,
    bool clearSuccess = false,
    bool clearTimer = false,
  }) {
    return ControlState(
      isLoading: isLoading ?? this.isLoading,
      isPumpOn: isPumpOn ?? this.isPumpOn,
      suhuMinLimit: suhuMinLimit ?? this.suhuMinLimit,
      suhuMaxLimit: suhuMaxLimit ?? this.suhuMaxLimit,
      kelembapanLimit: kelembapanLimit ?? this.kelembapanLimit,
      schedules: schedules ?? this.schedules,
      errorMessage: clearError ? null : (errorMessage ?? this.errorMessage),
      successMessage: clearSuccess ? null : (successMessage ?? this.successMessage),
      activePumpDuration: clearTimer ? null : (activePumpDuration ?? this.activePumpDuration),
      pumpTurnedOnAt: clearTimer ? null : (pumpTurnedOnAt ?? this.pumpTurnedOnAt),
      deviceMode: deviceMode ?? this.deviceMode,
      isModeLoading: isModeLoading ?? this.isModeLoading,
    );
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      (other is ControlState &&
          isLoading == other.isLoading &&
          isPumpOn == other.isPumpOn &&
          suhuMinLimit == other.suhuMinLimit &&
          suhuMaxLimit == other.suhuMaxLimit &&
          kelembapanLimit == other.kelembapanLimit &&
          errorMessage == other.errorMessage &&
          successMessage == other.successMessage &&
          activePumpDuration == other.activePumpDuration &&
          pumpTurnedOnAt == other.pumpTurnedOnAt &&
          schedules == other.schedules);

  @override
  int get hashCode =>
      isLoading.hashCode ^
      isPumpOn.hashCode ^
      suhuMinLimit.hashCode ^
      suhuMaxLimit.hashCode ^
      kelembapanLimit.hashCode ^
      errorMessage.hashCode ^
      successMessage.hashCode ^
      activePumpDuration.hashCode ^
      pumpTurnedOnAt.hashCode ^
      schedules.hashCode;
}
