# -*- coding: UTF-8 -*-
import attr
import random
import requests, json, os, hashlib, time
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from concurrent.futures import ThreadPoolExecutor, as_completed
import urllib3
from . import _util, _exception

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class State(object):
	def __init__(cls):
		cls._config = {}
		cls._headers = _util.HEADERS
		cls._cookies = _util.COOKIES
		cls._session = requests.Session()
		cls._session.trust_env = False
		adapter = HTTPAdapter(pool_connections=1000000, pool_maxsize=100000, max_retries=Retry(total=3, backoff_factor=0.2, status_forcelist=(500, 502, 504), allowed_methods=frozenset(["GET","POST","PUT","DELETE","HEAD","OPTIONS"])), pool_block=False)
		cls._session.mount("https://", adapter)
		cls._session.mount("http://", adapter)
		cls.user_id = None
		cls.user_imei = None
		cls._loggedin = False
		
	def requestSession(cls):
		return cls_session
		
	def get_cookies(cls):
		return cls._cookies

	def set_cookies(cls, cookies):
		cls._cookies = cookies

	def get_secret_key(cls):
		return cls._config.get("secret_key")

	def set_secret_key(cls, secret_key):
		cls._config["secret_key"] = secret_key

	def _get(cls, *args, **kwargs):
		sessionObj = cls._session.get(*args, **kwargs, headers=cls._headers, cookies=cls._cookies, timeout=5, verify=False)
		return sessionObj

	def _post(cls, *args, **kwargs):
		sessionObj = cls._session.post(*args, **kwargs, headers=cls._headers, cookies=cls._cookies, timeout=5, verify=False)
		return sessionObj

	def is_logged_in(cls):
		return cls._loggedin

	def get_state_filename(cls):
		dir_path = os.path.join("zlapi", "login")
		if not os.path.exists(dir_path):
			os.makedirs(dir_path)
		cookie_str = json.dumps(cls._cookies, sort_keys=True)
		cookie_hash = hashlib.md5(cookie_str.encode("utf-8")).hexdigest()
		filename = os.path.join(dir_path, f"state_{cookie_hash}.json")
		return filename

	def load_state(cls):
		filename = cls.get_state_filename()
		if os.path.exists(filename):
			with open(filename, "r", encoding="utf-8") as f:
				data = json.load(f)
			cls._config = data.get("config", {})
			cls._cookies = data.get("cookies", {})
			cls.user_id = cls._config.get("send2me_id")
			cls._loggedin = True if cls._config.get("secret_key") else False

	def save_state(cls):
		filename = cls.get_state_filename()
		data = {
			"config": cls._config,
			"cookies": cls._cookies
		}
		with open(filename, "w", encoding="utf-8") as f:
			json.dump(data, f, indent=2)

	def login(cls, phone, password, imei, session_cookies=None, user_agent=None):
		try:
			cls.load_state()
		except Exception as e:
			pass

		if cls._cookies and cls._config.get("secret_key"):
			# print(f"Login with about api\n{cls._config}")
			cls._loggedin = True
			return

		if user_agent:
			cls._headers["User-Agent"] = user_agent

		if cls._cookies:
			try:
				response = cls._get(f"https://wpa.chat.zalo.me/api/login/getLoginInfo?imei={imei}&type=24&client_version=655&computer_name=Tahn Dev Is Very Handsome!!!&ts={_util.now()}")
				data = response.json()
				content = {
					"data": {
						"phone_number": str(data["data"]["phone_number"]),
						"secret_key": str(data["data"]["zpw_enk"]),
						"send2me_id": str(data["data"]["uid"]),
						"zpw_ws": data["data"]["zpw_ws"],
						"cloud_id": data["data"]["send2me_id"],
					},
					"error_code": 0
				}
				# print(f"Login with cookies\n{content}")
				if content.get("error_code") == 0:
					cls._config = content.get("data")
					if cls._config.get("secret_key"):
						cls._loggedin = True
						cls.user_id = cls._config.get("send2me_id")
						cls.user_imei = imei
						cls.save_state()
					else:
						cls._loggedin = False
						raise _exception.ZaloLoginError("Unable to get `secret key`.")
				else:
					error = data.get("error_code")
					err_msg = data.get("error_message")
					raise _exception.ZaloLoginError(f"Error #{error} when logging in: {err_msg}")
			except _exception.ZaloLoginError as e:
				raise _exception.ZaloLoginError(str(e))
			except Exception as e:
				raise _exception.ZaloLoginError(f"An error occurred while logging in! {data}")
		else:
			raise _exception.LoginMethodNotSupport("Login method is not supported yet")
