import sys, json, logging, os, urllib.request, time
sys.path.insert(0, '/home/jay/projects/ThreadAuto')
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(name)s %(levelname)s %(message)s')
logger = logging.getLogger(__name__)

OUTPUT_DIR = '/home/jay/projects/ThreadAuto/output'
RESULT_PATH = f'{OUTPUT_DIR}/task680_result.json'
VERIFY_PATH = f'{OUTPUT_DIR}/task680_verification.json'
THREADS_BASE_URL = 'https://graph.threads.net/v1.0'

# ============================================================
# Step 1: 토픽 선택
# ============================================================
logger.info("=== Step 1: 토픽 선택 ===")
from content.topic_selector import select_single_topic
topic = select_single_topic(category="정보제공")
logger.info("선택된 토픽: %s", json.dumps(topic, ensure_ascii=False, indent=2))

# ============================================================
# Step 2: FiveStagePipeline으로 콘텐츠 생성
# ============================================================
logger.info("=== Step 2: FiveStagePipeline 콘텐츠 생성 (약 10분 소요) ===")
from content.five_stage_pipeline import FiveStagePipeline
pipeline = FiveStagePipeline()
result = pipeline.generate(topic=topic, content_type="cardnews")
logger.info("파이프라인 결과 키: %s", list(result.keys()))
logger.info("slides 수: %d", len(result.get("slides", [])))

# 결과 저장
with open(RESULT_PATH, 'w', encoding='utf-8') as f:
    json.dump(result, f, ensure_ascii=False, indent=2)
logger.info("파이프라인 결과 저장: %s", RESULT_PATH)

# ============================================================
# Step 3+4: ThreadsPublisher.publish_cardnews()로 렌더링+업로드
# ============================================================
logger.info("=== Step 3+4: 카드뉴스 렌더링 + Threads Carousel 업로드 ===")
from publisher.threads_publisher import ThreadsPublisher
publisher = ThreadsPublisher()

title = result.get("topic_id", topic.get("title", "보험 정보"))
items = []
if "slides" in result:
    for slide in result["slides"]:
        items.append({
            "title": slide.get("title", ""),
            "description": slide.get("text", slide.get("subtitle", ""))
        })

caption = result.get("caption", "")
hashtags = result.get("hashtags", [])

publish_result = publisher.publish_cardnews(
    title=title,
    items=items,
    caption=caption,
    hashtags=hashtags,
    content=result,
)

logger.info("발행 결과: %s", json.dumps(publish_result, ensure_ascii=False, default=str))

# ============================================================
# Step 5: 검증
# ============================================================
logger.info("=== Step 5: 검증 시작 ===")

verification = {
    "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S"),
    "publish_result": publish_result,
    "step1_image_files": {},
    "step2_image_urls": {},
    "step3_threads_api": {},
    "overall_success": False,
    "failure_reasons": [],
}

# ------- 검증 1: 이미지 파일 검증 -------
logger.info("--- 검증 1: PNG 파일 존재 및 크기 확인 ---")
image_paths = publish_result.get("image_paths", [])
img_file_results = {}

if not image_paths:
    msg = "image_paths가 비어 있음 — 렌더링 실패 의심"
    logger.error(msg)
    verification["failure_reasons"].append(msg)
else:
    for path in image_paths:
        try:
            size = os.path.getsize(path)
            ok = size > 10 * 1024  # 10KB 이상
            img_file_results[path] = {"exists": True, "size_bytes": size, "ok": ok}
            if ok:
                logger.info("이미지 파일 OK: %s (%d bytes)", path, size)
            else:
                msg = f"이미지 파일 크기 부족: {path} ({size} bytes < 10KB)"
                logger.warning(msg)
                verification["failure_reasons"].append(msg)
        except FileNotFoundError:
            img_file_results[path] = {"exists": False, "size_bytes": 0, "ok": False}
            msg = f"이미지 파일 없음: {path}"
            logger.error(msg)
            verification["failure_reasons"].append(msg)
        except Exception as e:
            img_file_results[path] = {"exists": False, "size_bytes": 0, "ok": False, "error": str(e)}
            msg = f"이미지 파일 확인 오류: {path} — {e}"
            logger.error(msg)
            verification["failure_reasons"].append(msg)

verification["step1_image_files"] = {
    "count": len(image_paths),
    "minimum_required": 3,
    "count_ok": len(image_paths) >= 3,
    "files": img_file_results,
    "all_ok": len(image_paths) >= 3 and all(v.get("ok") for v in img_file_results.values()),
}
logger.info("이미지 파일 수: %d (최소 3장 필요: %s)", len(image_paths), len(image_paths) >= 3)

if len(image_paths) < 3:
    verification["failure_reasons"].append(f"이미지 파일이 3장 미만: {len(image_paths)}장")

# ------- 검증 2: 이미지 URL 접근성 검증 -------
logger.info("--- 검증 2: 이미지 URL HTTP HEAD 접근성 확인 ---")
BASE_URL = "https://aidevserver.tail2cdab6.ts.net/images"
OUTPUT_DIR_PATH = '/home/jay/projects/ThreadAuto/output'
url_results = {}

for path in image_paths:
    # 파일명에서 URL 생성 (output 디렉토리 기준)
    filename = os.path.basename(path)
    # output 디렉토리 내 상대경로 계산
    try:
        rel = os.path.relpath(path, OUTPUT_DIR_PATH)
        image_url = f"{BASE_URL}/{rel}"
    except ValueError:
        image_url = f"{BASE_URL}/{filename}"

    try:
        req = urllib.request.Request(image_url, method="HEAD")
        with urllib.request.urlopen(req, timeout=15) as resp:
            status = resp.status
            content_type = resp.headers.get("Content-Type", "")
            ok = status == 200
            url_results[image_url] = {
                "status": status,
                "content_type": content_type,
                "ok": ok,
            }
            logger.info("URL 접근 %s: %s (status=%d, content_type=%s)",
                        "OK" if ok else "FAIL", image_url, status, content_type)
            if not ok:
                verification["failure_reasons"].append(f"URL 접근 실패 (HTTP {status}): {image_url}")
    except urllib.error.HTTPError as e:
        url_results[image_url] = {"status": e.code, "ok": False, "error": str(e)}
        msg = f"URL HTTP 오류 ({e.code}): {image_url}"
        logger.error(msg)
        verification["failure_reasons"].append(msg)
    except urllib.error.URLError as e:
        url_results[image_url] = {"status": 0, "ok": False, "error": str(e.reason)}
        msg = f"URL 접근 불가 (URLError): {image_url} — {e.reason}"
        logger.error(msg)
        verification["failure_reasons"].append(msg)
    except Exception as e:
        url_results[image_url] = {"status": 0, "ok": False, "error": str(e)}
        msg = f"URL 확인 오류: {image_url} — {e}"
        logger.error(msg)
        verification["failure_reasons"].append(msg)

verification["step2_image_urls"] = {
    "urls": url_results,
    "all_ok": bool(url_results) and all(v.get("ok") for v in url_results.values()),
}

# ------- 검증 3: Threads API 게시물 조회 -------
logger.info("--- 검증 3: Threads API 게시물 조회 및 media_type 검증 ---")
threads_post_id = publish_result.get("threads_post_id")

if not threads_post_id or not publish_result.get("success"):
    msg = f"업로드 실패 또는 post_id 없음. success={publish_result.get('success')}, error={publish_result.get('error')}"
    logger.error(msg)
    verification["failure_reasons"].append(msg)
    verification["step3_threads_api"] = {"success": False, "error": msg}
else:
    logger.info("Threads post_id: %s", threads_post_id)

    # 토큰 취득
    from auth.token_store import get_valid_token
    access_token = get_valid_token()

    if not access_token:
        msg = "액세스 토큰 취득 실패"
        logger.error(msg)
        verification["failure_reasons"].append(msg)
        verification["step3_threads_api"] = {"success": False, "error": msg}
    else:
        # GET /{post_id}?fields=id,media_type,children{id,media_type}
        fields = "id,media_type,children{id,media_type}"
        api_url = f"{THREADS_BASE_URL}/{threads_post_id}?fields={fields}&access_token={access_token}"
        logger.info("Threads API 조회: GET /%s?fields=%s", threads_post_id, fields)

        # 업로드 직후 API 조회 전 잠시 대기 (Threads 처리 시간)
        logger.info("Threads API 처리 대기 (5초)...")
        time.sleep(5)

        try:
            req = urllib.request.Request(api_url, method="GET")
            req.add_header("Accept", "application/json")
            with urllib.request.urlopen(req, timeout=30) as resp:
                api_data = json.loads(resp.read().decode('utf-8'))

            logger.info("Threads API 응답: %s", json.dumps(api_data, ensure_ascii=False, indent=2))

            media_type = api_data.get("media_type", "")
            is_carousel = media_type == "CAROUSEL_ALBUM"

            # children 검증
            children_data = api_data.get("children", {})
            children_list = children_data.get("data", []) if isinstance(children_data, dict) else []
            children_all_image = all(c.get("media_type") == "IMAGE" for c in children_list) if children_list else False

            verification["step3_threads_api"] = {
                "success": True,
                "post_id": api_data.get("id"),
                "media_type": media_type,
                "is_carousel_album": is_carousel,
                "children_count": len(children_list),
                "children": children_list,
                "children_all_image": children_all_image,
                "raw_response": api_data,
            }

            if is_carousel:
                logger.info("검증 성공: media_type = CAROUSEL_ALBUM")
            else:
                msg = f"media_type 검증 실패: 기대값=CAROUSEL_ALBUM, 실제값={media_type}"
                logger.error(msg)
                verification["failure_reasons"].append(msg)

            if children_list and not children_all_image:
                msg = f"children 타입 검증 실패: IMAGE가 아닌 아이템 포함"
                logger.warning(msg)
                verification["failure_reasons"].append(msg)

            if not children_list:
                logger.warning("children 목록이 비어 있음 (API가 children 필드를 반환하지 않을 수 있음)")

        except urllib.error.HTTPError as e:
            error_body = e.read().decode('utf-8', errors='replace') if hasattr(e, 'read') else ""
            msg = f"Threads API HTTP 오류 ({e.code}): {error_body[:500]}"
            logger.error(msg)
            verification["failure_reasons"].append(msg)
            verification["step3_threads_api"] = {"success": False, "error": msg, "http_code": e.code}
        except Exception as e:
            msg = f"Threads API 조회 오류: {e}"
            logger.error(msg)
            verification["failure_reasons"].append(msg)
            verification["step3_threads_api"] = {"success": False, "error": msg}

# ------- 최종 검증 결과 -------
step1_ok = verification["step1_image_files"].get("all_ok", False)
step2_ok = verification["step2_image_urls"].get("all_ok", False)
step3_ok = (
    verification["step3_threads_api"].get("success", False) and
    verification["step3_threads_api"].get("is_carousel_album", False)
)

verification["overall_success"] = step1_ok and step3_ok  # URL 접근성은 네트워크 환경에 따라 변동 가능
verification["step_summary"] = {
    "step1_image_files_ok": step1_ok,
    "step2_image_urls_ok": step2_ok,
    "step3_carousel_album_ok": step3_ok,
}

# 검증 결과 저장
with open(VERIFY_PATH, 'w', encoding='utf-8') as f:
    json.dump(verification, f, ensure_ascii=False, indent=2, default=str)
logger.info("검증 결과 저장: %s", VERIFY_PATH)

# ============================================================
# 최종 요약 출력
# ============================================================
print("\n" + "="*70)
print("=== task-680.1 최종 결과 ===")
print(f"발행 성공: {publish_result.get('success')}")
print(f"Threads Post ID: {publish_result.get('threads_post_id')}")
print(f"에러: {publish_result.get('error')}")
print(f"이미지 파일 수: {len(image_paths)}")
print(f"이미지 경로: {publish_result.get('image_paths', [])}")
print()
print(f"[검증 1] 이미지 파일 OK: {step1_ok}")
print(f"[검증 2] 이미지 URL 접근성 OK: {step2_ok}")
print(f"[검증 3] Carousel Album 검증 OK: {step3_ok}")
if verification["step3_threads_api"].get("media_type"):
    print(f"  media_type: {verification['step3_threads_api']['media_type']}")
    print(f"  children 수: {verification['step3_threads_api'].get('children_count', 'N/A')}")
print()
print(f"전체 검증 성공: {verification['overall_success']}")
if verification["failure_reasons"]:
    print("실패 원인:")
    for reason in verification["failure_reasons"]:
        print(f"  - {reason}")
print("="*70)
print(f"파이프라인 결과: {RESULT_PATH}")
print(f"검증 결과: {VERIFY_PATH}")
print("="*70)
