import 'dart:io';

import 'package:adjust_sdk/adjust.dart';
import 'package:flutter/foundation.dart';
import 'package:uuid/uuid.dart';
import 'package:android_id/android_id.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_vpn_detector/vpn_checker.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:play_install_referrer/play_install_referrer.dart';
import 'package:shared_preferences/shared_preferences.dart';

class DeviceInfo {
  static const String _spInstallReferrer = "installReferrer";
  static const int defaultTimeout = 1000;
  static const int defaultMaxTimeout = 2000;
  DeviceInfo._();
  static final DeviceInfo I = DeviceInfo._();
  Future<Map<String, dynamic>> deviceInfo({
    int adidTimeout = -1,
    bool includeInstallReferrer = false,
    bool includeAdjust = true,
  }) async {
    final Map<String, dynamic> json = {};

    try {
      adidTimeout = getTimeOut(adidTimeout);
      final packageInfo = await PackageInfo.fromPlatform();
      final devicePlugin = DeviceInfoPlugin();

      final locale = PlatformDispatcher.instance.locale;
      bool isActive = await VpnChecker.isVpnActive();
      json["isVpn"] = isActive;
      json["country"] = locale.countryCode;
      json["language"] = locale.languageCode;
      json["packageName"] = packageInfo.packageName;
      json["versionName"] = packageInfo.version;
      json["versionCode"] = packageInfo.buildNumber;
      if (Platform.isAndroid) {
        final androidInfo = await devicePlugin.androidInfo;

        json["osVersion"] = androidInfo.version.release;
        json["sdkInt"] = androidInfo.version.sdkInt.toString();
        json["brand"] = androidInfo.brand;
        json["model"] = androidInfo.model;
        json["device"] = androidInfo.device;
        json["androidId"] = await getAndroidId();
      } else if (Platform.isIOS) {
        final iosInfo = await devicePlugin.iosInfo;
        json["osVersion"] = iosInfo.systemVersion;
        json["model"] = iosInfo.model;
        json["device"] = iosInfo.modelName;
        json["androidId"] = iosInfo.identifierForVendor;
        json['idfv'] = iosInfo.identifierForVendor;
        try {
          json['idfa'] = await Adjust.getIdfa();
          if (includeAdjust) {
            json['adjustAdId'] = await Adjust.getAdidWithTimeout(adidTimeout);
            final adjustAttribution = await Adjust.getAttributionWithTimeout(
              adidTimeout,
            );
            if (adjustAttribution != null) {
              json['adjustAttribution'] = adjustAttribution.jsonResponse;
              json["clickLable"] = adjustAttribution.clickLabel;
            }
          }
        } catch (_) {}

        debugPrint("$iosInfo");
      }

      if (includeInstallReferrer) {
        final installReferrer = await getInstallReferrer(timeout: adidTimeout);
        if (installReferrer != null && installReferrer.isNotEmpty) {
          json["installReferrer"] = installReferrer;
        }
      }
    } catch (e) {
      debugPrint("[DeviceInfo] load adjust/referrer failed: $e");
    }

    return json;
  }

  Future<String?> getInstallReferrer({int timeout = 2000}) async {
    try {
      final prefs = await SharedPreferences.getInstance();
      final cachedReferrer = prefs.getString(_spInstallReferrer);
      if (cachedReferrer != null && cachedReferrer.isNotEmpty) {
        return cachedReferrer;
      }

      final referrerDetails = await PlayInstallReferrer.installReferrer.timeout(
        Duration(milliseconds: timeout),
      );
      final referrer = referrerDetails.installReferrer;

      if (referrer != null && referrer.isNotEmpty) {
        await prefs.setString(_spInstallReferrer, referrer);
      }
      return referrer;
    } catch (e) {
      debugPrint("[DeviceInfo] get install referrer failed: $e");
      return null;
    }
  }

  int getTimeOut(int timeout) {
    if (timeout <= 0) {
      return defaultTimeout;
    }
    return timeout;
  }

  Future<String> getAndroidId() async {
    try {
      AndroidId androidIdPlugin = AndroidId();
      final androidId = await androidIdPlugin.getId();
      return androidId ?? await createDeviceId();
    } catch (e) {
      debugPrint("[DeviceInfo] get Android ID failed: $e");
      return '';
    }
  }

  Future<String> createDeviceId() async {
    const key = "createdDeviceId";
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? deviceId = prefs.getString(key);
    if (deviceId != null && deviceId.isNotEmpty) {
      return deviceId;
    }
    final uuid = const Uuid();
    deviceId = uuid.v4();
    deviceId = deviceId.replaceAll('-', '');
    await prefs.setString(key, deviceId);
    return deviceId;
  }
}
