import 'dart:convert';

import 'package:agrilink_vocpro/core/constant/app_constant.dart';
import 'package:agrilink_vocpro/core/extension/extention.dart';
import 'package:agrilink_vocpro/data/model/dht_graphic_response.dart';
import 'package:agrilink_vocpro/data/model/jwt_token_response.dart';
import 'package:agrilink_vocpro/data/model/login_response.dart';
import 'package:agrilink_vocpro/data/model/npk1_graphic_response.dart';
import 'package:agrilink_vocpro/data/model/npk2_graphic_response.dart';
import 'package:agrilink_vocpro/data/model/relay_response.dart';
import 'package:agrilink_vocpro/data/model/latest_data_response.dart';
import 'package:agrilink_vocpro/data/model/switch_relay_response.dart';
import 'package:dio/dio.dart';
import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AppService {
  final Dio _dioWithoutInterceptor = Dio(
    BaseOptions(
      baseUrl: AppConstant.baseUrl,
      connectTimeout: Duration(seconds: 5),
      receiveTimeout: Duration(seconds: 5),
    ),
  );

  Future<LoginResponse> login({
    required String username,
    required String password,
    String rememberMe = 'false',
  }) async {
    final SharedPreferences pref = await SharedPreferences.getInstance();
    final String basicAuth =
        'Basic ${base64Encode(utf8.encode('$username:$password'))}';

    FormData formData = FormData.fromMap({
      'remember_me': rememberMe,
    });

    try {
      final response = await _dioWithoutInterceptor.post(
        '/auth/login',
        data: formData,
        options: Options(
          headers: {
            'Authorization': basicAuth,
          },
        ),
      );

      if (response.statusCode == 200) {
        final data = LoginResponse.fromJson(response.data);
        final decodedToken =
            JwtTokenResponse.fromJson(JwtDecoder.decode(data.data!.jwtToken!));
        pref.setString('token', data.data!.token!);
        pref.setString('jwtToken', data.data!.jwtToken!);
        pref.setString('username', decodedToken.user?.username ?? 'unknown');
        pref.setString('email', decodedToken.user?.email ?? 'unknown');
        pref.setString('fullName', decodedToken.user?.fullname ?? 'unknown');
        pref.setBool('isLoggedIn', true);
        return data;
      } else {
        throw Exception('Failed to load data');
      }
    } on DioException catch (e) {
      final String errorMessage;
      if (e.response?.data != null) {
        errorMessage = e.response?.data['message'] ?? 'Something went wrong';
      } else {
        errorMessage = 'Something went wrong';
      }
      throw (errorMessage);
    }
  }

  // logout
  Future<LoginResponse> logout() async {
    final SharedPreferences pref = await SharedPreferences.getInstance();
    final String auth = 'Bearer ${pref.getString('token')}';

    try {
      final response = await _dioWithoutInterceptor.post(
        '/auth/logout',
        options: Options(
          headers: {'Authorization': auth},
        ),
      );
      if (response.statusCode == 200) {
        final data = LoginResponse.fromJson(response.data);
        pref.remove('token');
        pref.remove('jwtToken');
        pref.remove('username');
        pref.remove('email');
        pref.remove('fullName');
        pref.setBool('isLoggedIn', false);
        return data;
      } else {
        throw Exception('Failed to load data');
      }
    } on DioException catch (e) {
      final String errorMessage = e.response?.data['message'];
      throw (errorMessage);
    }
  }

  Future<RelayResponse> getRelayStatus() async {
    final SharedPreferences pref = await SharedPreferences.getInstance();
    final String auth = 'Bearer ${pref.getString('token')}';
    try {
      await Future.delayed(const Duration(seconds: 3));
      final response = await _dioWithoutInterceptor.get(
        '/api/relay/get-relay',
        options: Options(
          headers: {'Authorization': auth},
        ),
      );
      if (response.statusCode == 200) {
        final data = RelayResponse.fromJson(response.data);
        return data;
      } else {
        throw Exception('Failed to load data');
      }
    } on DioException catch (e) {
      final errorMessage = e.response?.data['message'];
      throw (errorMessage);
    }
  }

  // switch relay

  Future<SwitchRelayResponse> switchRelay(
      {required int relayNumber, required int state}) async {
    final SharedPreferences pref = await SharedPreferences.getInstance();
    final String auth = 'Bearer ${pref.getString('token')}';

    try {
      final response = await _dioWithoutInterceptor.post(
        '/api/relay/set-relay',
        data: {
          'id': relayNumber,
          'state': state,
        },
        options: Options(
          headers: {'Authorization': auth},
        ),
      );

      if (response.statusCode == 200 || response.statusCode == 201) {
        final data = SwitchRelayResponse.fromJson(response.data);
        return data;
      } else {
        throw Exception('Failed to load data');
      }
    } on DioException catch (e) {
      final errorMessage = e.response?.data['message'];
      throw (errorMessage);
    }
  }

  //get grafik data dht

  Future<DhtGraphicResponse> getGrafikDataDht({
    required String metric,
  }) async {
    final SharedPreferences pref = await SharedPreferences.getInstance();
    final String auth = 'Bearer ${pref.getString('token')}';
    String date = DateTime.now().toString();
    final formatedDate = dateFormatterShort(date);
    try {
      final result = await _dioWithoutInterceptor.get(
        '/api/sensor/getData?metric=$metric&range[start]=$formatedDate&range[end]=$formatedDate&range[time_range]=HOURLY&sensor=dht',
        options: Options(
          headers: {'Authorization': auth},
        ),
      );
      if (result.statusCode == 200) {
        final data = DhtGraphicResponse.fromJson(result.data);
        return data;
      } else {
        throw Exception('Failed to load data');
      }
    } on DioException catch (e) {
      final errorMessage = e.response?.data['message'];
      throw (errorMessage);
    }
  }

// get grafik data npk1
  Future<Npk1GraphicResponse> getGraphicDataNpk1(
      {required String metric}) async {
    final SharedPreferences pref = await SharedPreferences.getInstance();
    final String auth = 'Bearer ${pref.getString('token')}';
    String date = DateTime.now().toString();
    final formatedDate = dateFormatterShort(date);
    try {
      final result = await _dioWithoutInterceptor.get(
        '/api/sensor/getData?metric=$metric&range[start]=$formatedDate&range[end]=$formatedDate&range[time_range]=HOURLY&sensor=npk1',
        options: Options(
          headers: {'Authorization': auth},
        ),
      );
      if (result.statusCode == 200) {
        final data = Npk1GraphicResponse.fromJson(result.data);
        return data;
      } else {
        throw Exception('Failed to load data');
      }
    } on DioException catch (e) {
      final errorMessage = e.response?.data['message'];
      throw (errorMessage);
    }
  }

  // get grafik data npk2

  Future<Npk2GraphicResponse> getGraphicDataNpk2(
      {required String metric}) async {
    final SharedPreferences pref = await SharedPreferences.getInstance();
    final String auth = 'Bearer ${pref.getString('token')}';
    String date = DateTime.now().toString();
    final formatedDate = dateFormatterShort(date);
    try {
      final result = await _dioWithoutInterceptor.get(
        '/api/sensor/getData?metric=$metric&range[start]=$formatedDate&range[end]=$formatedDate&range[time_range]=HOURLY&sensor=npk2',
        options: Options(
          headers: {'Authorization': auth},
        ),
      );
      if (result.statusCode == 200) {
        final data = Npk2GraphicResponse.fromJson(result.data);
        return data;
      } else {
        throw Exception('Failed to load data');
      }
    } on DioException catch (e) {
      final errorMessage = e.response?.data['message'];
      throw (errorMessage);
    }
  }

  // get latest data

  Future<LatestDataResponse> getLatestData() async {
    final SharedPreferences pref = await SharedPreferences.getInstance();
    final String auth = 'Bearer ${pref.getString('token')}';
    try {
      final result = await _dioWithoutInterceptor.get(
        '/api/sensor/getLatest',
        options: Options(
          headers: {'Authorization': auth},
        ),
      );
      if (result.statusCode == 200) {
        final data = LatestDataResponse.fromJson(result.data);
        return data;
      } else {
        throw Exception('Failed to load data');
      }
    } on DioException catch (e) {
      final errorMessage = e.response?.data['message'];
      throw (errorMessage);
    }
  }
}
