#!/usr/bin/env python3
import base64
import hashlib
import hmac
import json
import os
import time
import urllib.error
import urllib.parse
import urllib.request
from typing import Any, Optional

sys_path_inserted = False
try:
    import sys

    if "/home/jay/workspace" not in sys.path:
        sys.path.insert(0, "/home/jay/workspace")
    sys_path_inserted = True
except Exception:
    pass

from utils.env_loader import load_env_keys  # type: ignore[import-not-found]
from utils.logger import get_logger  # type: ignore[import-not-found]

logger = get_logger(__name__)

_BASE_URL = "https://api.searchad.naver.com"
_DEFAULT_FIELDS = ["impCnt", "clkCnt", "salesAmt", "ctr", "cpc", "ccnt"]


class NaverSAClient:
    def __init__(self, env_keys_path: str = "/home/jay/workspace/.env.keys") -> None:
        load_env_keys(env_keys_path)
        self._customer_id = os.environ.get("NAVER_SEARCHAD_CUSTOMER_ID", "")
        self._api_key = os.environ.get("NAVER_SEARCHAD_API_KEY", "")
        self._secret_key = os.environ.get("NAVER_SEARCHAD_SECRET_KEY", "")
        if not all([self._customer_id, self._api_key, self._secret_key]):
            logger.warning("NAVER_SEARCHAD 환경변수 일부 누락")
        logger.info("NaverSAClient 초기화 완료 (customer_id=%s)", self._customer_id)

    def _generate_signature(self, timestamp: str, method: str, uri: str) -> str:
        message = f"{timestamp}.{method}.{uri}"
        h = hmac.new(
            self._secret_key.encode("utf-8"),
            message.encode("utf-8"),
            hashlib.sha256,
        )
        return base64.b64encode(h.digest()).decode("utf-8")

    def _build_headers(self, method: str, uri: str) -> dict:
        timestamp = str(int(time.time() * 1000))
        return {
            "X-Timestamp": timestamp,
            "X-API-KEY": self._api_key,
            "X-Customer": self._customer_id,
            "X-Signature": self._generate_signature(timestamp, method, uri),
            "Content-Type": "application/json; charset=UTF-8",
        }

    def _request(
        self,
        method: str,
        uri: str,
        params: Optional[dict] = None,
    ) -> Any:
        url = _BASE_URL + uri
        if params:
            url += "?" + urllib.parse.urlencode(params, doseq=True)

        max_retries = 3
        for attempt in range(max_retries):
            headers = self._build_headers(method, uri)
            req = urllib.request.Request(url, headers=headers, method=method)
            try:
                with urllib.request.urlopen(req, timeout=30) as resp:
                    body = resp.read().decode("utf-8")
                    return json.loads(body) if body else {}
            except urllib.error.HTTPError as e:
                if e.code == 429:
                    wait = 2**attempt
                    logger.warning("Rate limit (429), %d초 후 재시도 (attempt=%d)", wait, attempt + 1)
                    time.sleep(wait)
                    continue
                body = e.read().decode("utf-8", errors="replace")
                logger.error("HTTP %d %s %s: %s", e.code, method, uri, body)
                raise
            except Exception as e:
                logger.error("요청 실패 (attempt=%d): %s %s — %s", attempt + 1, method, uri, e)
                if attempt < max_retries - 1:
                    time.sleep(2**attempt)
                    continue
                raise
        raise RuntimeError(f"최대 재시도 초과: {method} {uri}")

    def get_campaigns(self) -> list:
        result = self._request("GET", "/ncc/campaigns")
        return result if isinstance(result, list) else result.get("items", [result]) if isinstance(result, dict) else []

    def get_adgroups(self, campaign_id: Optional[str] = None) -> list:
        params = {}
        if campaign_id:
            params["nccCampaignId"] = campaign_id
        result = self._request("GET", "/ncc/adgroups", params=params or None)
        return result if isinstance(result, list) else result.get("items", [result]) if isinstance(result, dict) else []

    def get_keywords(self, adgroup_id: str) -> list:
        result = self._request("GET", "/ncc/keywords", params={"nccAdgroupId": adgroup_id})
        return result if isinstance(result, list) else result.get("items", [result]) if isinstance(result, dict) else []

    def get_stats(
        self,
        ids: list,
        fields: Optional[list] = None,
        date_preset: Optional[str] = None,
        time_range: Optional[dict] = None,
        breakdown: Optional[str] = None,
    ) -> list:
        params: dict[str, Any] = {
            "ids": ids,
            "fields": json.dumps(fields if fields is not None else _DEFAULT_FIELDS),
        }
        if date_preset:
            params["datePreset"] = date_preset
        if time_range:
            params["timeRange"] = json.dumps(time_range)
        if breakdown:
            params["breakdown"] = breakdown

        result = self._request("GET", "/stats", params=params)
        if isinstance(result, list):
            return result
        if isinstance(result, dict):
            return result.get("data", result.get("items", []))
        return []
