import hashlib
from pathlib import Path

import cv2
from PIL import Image
import imagehash
from imwatermark import WatermarkEncoder, WatermarkDecoder


def sha256_file(path: Path) -> str:
    h = hashlib.sha256()
    with path.open("rb") as f:
        while True:
            chunk = f.read(8192)
            if not chunk:
                break
            h.update(chunk)
    return h.hexdigest()


def phash_file(path: Path) -> str:
    return str(imagehash.phash(Image.open(path)))


def phash_distance(hex1: str, hex2: str) -> int:
    return imagehash.hex_to_hash(hex1) - imagehash.hex_to_hash(hex2)


def embed_watermark(input_path: Path, output_path: Path, watermark_id: str):
    output_path.parent.mkdir(parents=True, exist_ok=True)
    bgr = cv2.imread(str(input_path))
    if bgr is None:
        raise ValueError(f"无法读取图片: {input_path}")

    encoder = WatermarkEncoder()
    encoder.set_watermark("bytes", watermark_id.encode("utf-8"))
    embedded = encoder.encode(bgr, "dwtDct")
    cv2.imwrite(str(output_path), embedded)


def extract_watermark(input_path: Path, wm_len_bytes: int = 8) -> str:
    try:
        bgr = cv2.imread(str(input_path))
        if bgr is None:
            return ""

        decoder = WatermarkDecoder("bytes", wm_len_bytes)
        wm_bytes = decoder.decode(bgr, "dwtDct")

        if isinstance(wm_bytes, bytes):
            return wm_bytes.decode("utf-8", errors="ignore").strip("\x00")
        return str(wm_bytes)
    except Exception:
        return ""


def attack_jpeg(input_path: Path, output_path: Path, quality: int = 70):
    img = Image.open(input_path).convert("RGB")
    output_path.parent.mkdir(parents=True, exist_ok=True)
    img.save(output_path, format="JPEG", quality=quality)


def attack_scale(input_path: Path, output_path: Path, scale: float = 0.5):
    img = Image.open(input_path).convert("RGB")
    w, h = img.size
    out = img.resize((max(1, int(w * scale)), max(1, int(h * scale))), Image.Resampling.LANCZOS)
    output_path.parent.mkdir(parents=True, exist_ok=True)
    out.save(output_path)


def attack_crop(input_path: Path, output_path: Path, ratio: float = 0.8):
    img = Image.open(input_path).convert("RGB")
    w, h = img.size
    new_w, new_h = int(w * ratio), int(h * ratio)
    left = (w - new_w) // 2
    top = (h - new_h) // 2
    out = img.crop((left, top, left + new_w, top + new_h))
    output_path.parent.mkdir(parents=True, exist_ok=True)
    out.save(output_path)


def attack_screenshot_like(input_path: Path, output_path: Path):
    img = Image.open(input_path).convert("RGB")
    w, h = img.size
    tmp = img.resize((max(1, int(w * 0.7)), max(1, int(h * 0.7))), Image.Resampling.BILINEAR)
    out = tmp.resize((w, h), Image.Resampling.BILINEAR)
    output_path.parent.mkdir(parents=True, exist_ok=True)
    out.save(output_path)
