import os
import struct
import pyzstd
import locale
import requests
from packaging import version as VER
from typing import Literal
from AoV_Dictionary import DICT_RAW
from importlib.metadata import version

__version__ = version("AoV_Zstd")

DICT = pyzstd.ZstdDict(DICT_RAW, is_raw = True)
language = locale.getlocale()[0] or ""

def XL(mode: Literal["d","c"], INP: str | bytes) -> str:
    """
    mode: The mode must be either "d" (decompress) or "c" (compress).\n
    INP: Is a filename as file path been to input
    """
    if mode == "d":
        result, notification = decompress(INP = INP)
    elif mode == "c":
        result, notification = compress(INP = INP)
    else:
        raise ValueError(Lang("Chế độ chỉ có \"d\" hoặc \"c\".", "The mode must be either \"d\" or \"c\"."))
    if not result:
        print("~", end = " ")
    print(notification)

def decompress(INP: str | bytes) -> tuple[bool,str]:
    T_en = f"\"{INP}\" Decompress Complete!"
    F_en = f"\"{INP}\" Unable to decompress!"
    T_vi = f"\"{INP}\" Giải nén thành công!"
    F_vi = f"\"{INP}\" Không thể giải nén!"
    if check_exists(INP = INP)[0]:
        with open(file = INP, mode = "rb") as f:
            header = f.read(8)
            type_ = header[0:4]
            size_ = header[4:8]
            if type_ == b"\x22\x4a\x00\xef":
                dt = f.read()
                expected_size = struct.unpack("<I", size_)[0]
                dl = dt[dt.find(b"\x28\xb5\x2f\xfd"):]
                try:
                    dctx = pyzstd.ZstdDecompressor(zstd_dict=DICT)
                    dl = dctx.decompress(data = dl, max_length = expected_size)
                    with open(file = INP, mode = "wb") as w:
                        w.write(dl)
                        return (True, Lang(T_vi, T_en))
                except pyzstd.ZstdError:
                    return (False, Lang(F_vi, F_en))
            else:
                return (False, Lang(F_vi, F_en))

def compress(INP: str | bytes) -> tuple[bool,str]:
    T_en = f"\"{INP}\" Compress Complete!"
    F_en = f"\"{INP}\" Unable to compress!"
    T_vi = f"\"{INP}\" Nén thành công!"
    F_vi = f"\"{INP}\" không thể nén!"
    if check_exists(INP = INP)[0]:
        type_ = [b"\x22\x4a\x00\xef", b"\x22\x4a\x67\x00"]
        with open(file = INP, mode = "rb") as f:
            header = f.read(8)
            if header[0:4] in type_:
                return (False, Lang(F_vi, F_en))
            else:
                dt = f.read()
                total_size = struct.pack("<I", len(dt))
                new_header = type_[0] + total_size
                try:
                    cctx = pyzstd.ZstdCompressor(level_or_option = 17, zstd_dict = DICT)
                    compressed = cctx.compress(data = dt, mode = 2)
                    dl = new_header + compressed + total_size + os.urandom(4)
                    with open(file = INP, mode = "wb") as w:
                        w.write(dl)
                        return (True, Lang(T_vi, T_en))
                except pyzstd.ZstdError:
                    return (False, Lang(F_vi, F_en))

def check_exists(INP: str | bytes) -> tuple[bool,str]:
    if not os.path.isfile(INP):
        return (False, Lang(f"\"{INP}\" không phải tệp hoặc không tồn tại!", f"\"{INP}\" is not a file or does not exist!"))
    return (True, "")

def Lang(vi: str, en: str) -> str:
    if language.lower().startswith("vi"):
        return vi
    else:
        return en

def check_version():
    try:
        url = f"https://pypi.org/pypi/AoV_Zstd/json"
        response = requests.get(url, timeout=5)
        latest_version = response.json()["info"]["version"]
        if VER.parse(latest_version) > VER.parse(__version__):
            print(Lang(f"Phiên bản mới ({latest_version}) của AoV_Zstd đã có. Sử dụng: \"pip install --upgrade AoV_Zstd\" để cập nhật!", f"A new version ({latest_version}) of AoV_Zstd is available. Use: \"pip install --upgrade AoV_Zstd\" to update!"))
    except Exception as Ex:
        print(Ex)

check_version()