# -*- coding: utf-8 -*-

import os
import sys
import json
import random
import re
import argparse
from datetime import datetime

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)

from db import get_conn

from services.ollama_writer import generate_ai_sections
from services.blog_layout_blocks import build_blog_html
from services.extra_image_service import get_extra_images_if_needed


def json_default(obj):
    if isinstance(obj, datetime):
        return obj.strftime("%Y-%m-%d %H:%M:%S")
    return str(obj)


def clean_text(value):
    return str(value or "").strip()


def pick_one(items):
    if not items:
        return ""
    return random.choice(items)


def pick_many(items, count=3):
    items = list(items or [])
    random.shuffle(items)
    return items[:count]


def normalize_floor_text(floor_info):
    floor_info = clean_text(floor_info)

    if not floor_info:
        return ""

    return floor_info.replace("층층", "층")


def detect_floor_type(floor_info):
    floor_info = clean_text(floor_info)

    if "/" not in floor_info:
        return ""

    try:
        current, total = floor_info.split("/", 1)
        current = int(str(current).replace("층", "").strip())
        total = int(str(total).replace("층", "").strip())

        if total <= 0:
            return ""

        ratio = current / total

        if ratio >= 0.7:
            return "high"

        if ratio <= 0.3:
            return "low"

        return "middle"

    except Exception:
        return ""


def detect_direction_type(direction):
    direction = clean_text(direction)

    if not direction:
        return ""

    if "남" in direction:
        return "south"

    if "동" in direction:
        return "east"

    if "서" in direction:
        return "west"

    if "북" in direction:
        return "north"

    return ""

DIRECTION_MAP = {
    "E": "동향",
    "W": "서향",
    "S": "남향",
    "N": "북향",

    "ES": "동남향",
    "SE": "남동향",

    "WS": "서남향",
    "SW": "남서향",

    "EN": "동북향",
    "NE": "북동향",

    "WN": "서북향",
    "NW": "북서향",
}


def convert_direction(direction_code):

    direction_code = clean_text(
        direction_code
    ).upper()

    if not direction_code:
        return ""

    return DIRECTION_MAP.get(
        direction_code,
        direction_code
    )


COMMENT_TITLES = [
    "현장 설명",
    "중개사 코멘트",
    "실제 매물 설명",
    "현장 체크 포인트",
]


COMMENT_OPENERS = [
    "중개사 설명 기준으로는",
    "현장 안내 내용을 보면",
    "실제 등록된 설명에서는",
    "대표 설명 기준으로는",
]


FEATURE_REWRITE_POOL = {

    "채광": [
        "채광 방향을 중요하게 보시는 분들께 참고가 될 수 있습니다.",
        "실내 채광 흐름을 함께 체크해보시면 좋겠습니다.",
    ],

    "남향": [
        "남향 기준이라 일조량 부분도 함께 참고해보시면 좋겠습니다.",
        "채광과 개방감을 중요하게 보시는 분들께 잘 맞을 수 있습니다.",
    ],

    "로얄": [
        "선호도 높은 라인과 층 조건을 함께 참고해보시면 좋겠습니다.",
    ],

    "뷰": [
        "개방감과 전망 부분도 함께 체크해보시면 좋겠습니다.",
    ],

    "수리": [
        "실내 컨디션과 관리 상태를 함께 참고해보시면 좋겠습니다.",
    ],

    "깨끗": [
        "실내 관리 상태가 비교적 안정적으로 유지된 느낌입니다.",
    ],
}


def split_feature_sentences(text):

    text = clean_text(text)

    if not text:
        return []

    separators = [
        "\n",
        ".",
        ",",
        "/",
        "·",
    ]

    items = [text]

    for sep in separators:

        temp = []

        for item in items:
            temp.extend(item.split(sep))

        items = temp

    result = []

    for item in items:

        item = clean_text(item)

        if len(item) < 2:
            continue

        if item in result:
            continue

        result.append(item)

    return result


def rewrite_feature_sentence(sentence):

    sentence = clean_text(sentence)

    if not sentence:
        return ""

    for keyword, pool in FEATURE_REWRITE_POOL.items():

        if keyword in sentence:
            return pick_one(pool)

    generic_pool = [
        f"{sentence} 부분을 함께 참고해보시면 좋겠습니다.",
        f"실제 현장에서는 {sentence} 부분도 체크해보시면 좋겠습니다.",
        f"공간 활용 측면에서 {sentence} 조건도 함께 확인해보시면 좋겠습니다.",
    ]

    return pick_one(generic_pool)


def build_feature_comment_block(detail):

    raw_text = clean_text(
        detail.get("article_feature_desc")
    )

    if not raw_text:
        return {
            "title": "",
            "content": "",
        }

    items = split_feature_sentences(raw_text)

    if not items:
        return {
            "title": "",
            "content": "",
        }

    selected = pick_many(items, 3)

    lines = []

    opener = pick_one(COMMENT_OPENERS)

    for idx, item in enumerate(selected):

        line = rewrite_feature_sentence(item)

        if idx == 0:
            line = f"{opener} {line}"

        lines.append(line)

    return {
        "title": pick_one(COMMENT_TITLES),
        "content": " ".join(lines)
    }


def normalize_duplicate_dong_text(text):
    text = clean_text(text)

    if not text:
        return ""

    text = re.sub(r"(\b\d{1,4}동)\s+\1\b", r"\1", text)

    parts = text.split()
    cleaned = []

    for part in parts:
        if cleaned and cleaned[-1] == part and re.search(r"\d+동$", part):
            continue

        cleaned.append(part)

    return " ".join(cleaned)


def choose_clean_article_name(detail):
    article_name = clean_text(detail.get("article_name"))
    building_name = clean_text(detail.get("building_name"))

    article_name = normalize_duplicate_dong_text(article_name)
    building_name = normalize_duplicate_dong_text(building_name)

    if article_name and building_name:
        if building_name in article_name:
            return article_name

        if article_name in building_name:
            return building_name

        return normalize_duplicate_dong_text(f"{article_name} {building_name}")

    return article_name or building_name or "해당 매물"


def build_intro_text(detail):
    article_name = choose_clean_article_name(detail)

    trade_type = clean_text(detail.get("trade_type"))
    real_estate_type = clean_text(detail.get("real_estate_type"))
    price_text = clean_text(detail.get("price_text"))
    area_info = clean_text(detail.get("area_info"))
    floor_info = normalize_floor_text(detail.get("floor_info"))
    direction = convert_direction(
        detail.get("direction")
        or detail.get("direction_code")
    )

    openers = [
        f"오늘은 {article_name} 매물을 자세히 소개해드리겠습니다.",
        f"이번에 확인해볼 매물은 {article_name}입니다.",
        f"{article_name} 매물을 찾고 계셨다면 한 번 살펴보셔도 좋겠습니다.",
        f"조건과 위치를 함께 보기에 좋은 {article_name} 매물입니다.",
        f"실거주 관점에서 체크해볼 만한 {article_name} 매물입니다.",
        f"오늘 소개할 곳은 문의가 꾸준히 이어지는 {article_name} 매물입니다.",
        f"사진과 기본 조건을 함께 보며 {article_name} 매물을 정리해드리겠습니다.",
        f"생활 편의성과 구조를 함께 살펴볼 수 있는 {article_name} 매물입니다.",
    ]

    second_lines = []

    if trade_type and real_estate_type:
        second_lines += [
            f"{real_estate_type} {trade_type} 매물로 현재 조건을 기준으로 안내드립니다.",
            f"{trade_type} 조건으로 나온 {real_estate_type} 매물입니다.",
            f"{real_estate_type}을 찾는 분들께 참고가 될 만한 {trade_type} 매물입니다.",
        ]
    elif trade_type:
        second_lines += [
            f"{trade_type} 조건으로 확인되는 매물입니다.",
            f"현재 {trade_type} 기준으로 안내 가능한 매물입니다.",
        ]

    if price_text:
        second_lines += [
            f"가격은 {price_text} 기준으로 확인됩니다.",
            f"현재 안내되는 가격 조건은 {price_text}입니다.",
            f"예산을 맞춰 비교해보실 때 {price_text} 조건을 기준으로 보시면 됩니다.",
        ]

    if area_info:
        second_lines += [
            f"면적은 {area_info} 기준으로 확인됩니다.",
            f"{area_info} 구조라 공간 활용을 함께 확인해보시면 좋습니다.",
            f"실사용 면적과 동선을 함께 보기 좋은 {area_info} 타입입니다.",
        ]

    if floor_info:
        second_lines += [
            f"층수는 {floor_info}으로 확인됩니다.",
            f"{floor_info} 조건이라 채광과 조망, 이동 동선을 함께 체크해보시면 좋습니다.",
        ]

    if direction:
        second_lines += [
            f"방향은 {direction} 기준으로 확인됩니다.",
            f"{direction} 기준이라 채광과 개방감을 중요하게 보시는 분들께 잘 맞을 수 있습니다.",
            f"{direction} 방향 기준으로 일조량 부분도 함께 참고해보시면 좋겠습니다.",
            f"{direction} 방향 특성을 고려해 실내 분위기를 함께 체크해보시면 좋겠습니다.",
        ]

    lines = [
        pick_one(openers),
        pick_one(second_lines) if second_lines else "",
    ]

    return "\n".join([x for x in lines if x])


def build_feature_text(detail):
    floor_info = clean_text(detail.get("floor_info"))
    direction = clean_text(detail.get("direction"))
    area_info = clean_text(detail.get("area_info"))
    real_estate_type = clean_text(detail.get("real_estate_type"))
    feature = clean_text(detail.get("article_feature") or detail.get("feature"))
    address = clean_text(detail.get("address") or detail.get("road_address"))

    floor_type = detect_floor_type(floor_info)
    direction_type = detect_direction_type(direction)

    pool = [
        "전체적으로 생활 동선이 무난하게 잡혀 있어 실거주 관점에서 보기 좋은 매물입니다.",
        "사진과 조건을 함께 비교해보면 기본기가 잘 갖춰진 매물로 볼 수 있습니다.",
        "처음 집을 보시는 분들도 구조와 조건을 비교하기 쉬운 타입입니다.",
        "실제 거주를 고려하신다면 채광, 동선, 주변 환경을 함께 보시면 좋습니다.",
        "가격 조건과 내부 컨디션을 함께 비교해볼 만한 매물입니다.",
        "같은 단지 안에서도 층수와 방향에 따라 체감이 달라질 수 있어 직접 확인을 추천드립니다.",
        "실사용 공간을 중요하게 보시는 분들께는 체크해볼 만한 매물입니다.",
        "주거 안정성과 생활 편의성을 함께 고려하시는 분들께 잘 맞을 수 있습니다.",
        "입주 일정과 조건만 맞는다면 충분히 관심 있게 보실 수 있는 매물입니다.",
        "단순히 가격만 보기보다는 위치, 구조, 관리 상태를 함께 확인하시는 것이 좋습니다.",
        "실내 동선과 수납, 채광 조건을 함께 비교해보면 판단이 쉬운 매물입니다.",
        "주변 생활권과 단지 분위기를 함께 고려하면 장점이 더 잘 보이는 매물입니다.",
    ]

    if direction_type == "south":
        pool += [
            "남향 계열 방향이라 채광을 중요하게 보시는 분들께 특히 참고가 됩니다.",
            "햇빛이 들어오는 시간대와 거실 방향을 함께 확인해보시면 만족도가 높을 수 있습니다.",
            "채광을 선호하시는 분들에게는 장점으로 볼 수 있는 방향 조건입니다.",
        ]

    if floor_type == "high":
        pool += [
            "상대적으로 높은 층에 해당해 개방감과 조망감을 기대해볼 수 있습니다.",
            "고층 선호도가 있는 분들께는 우선적으로 검토해볼 만한 조건입니다.",
        ]
    elif floor_type == "middle":
        pool += [
            "중간층에 가까운 조건이라 생활 편의성과 안정감 사이의 균형을 기대할 수 있습니다.",
            "층수 부담이 크지 않아 실거주용으로 무난하게 검토하기 좋습니다.",
        ]
    elif floor_type == "low":
        pool += [
            "저층부에 가까워 이동 편의성을 중요하게 보시는 분들께 참고가 됩니다.",
            "엘리베이터 대기나 이동 동선을 줄이고 싶은 분들에게 맞을 수 있습니다.",
        ]

    if area_info:
        pool += [
            "면적 구성을 보면 가족 구성원 수와 생활 패턴에 맞춰 판단하기 좋습니다.",
            "공간을 어떻게 나누어 사용할지 상상해보며 보시면 더 도움이 됩니다.",
        ]

    if real_estate_type:
        pool += [
            f"{real_estate_type} 특성상 관리 상태와 주변 환경을 함께 확인하는 것이 중요합니다.",
            f"{real_estate_type}을 찾는 분들이 주로 보는 조건들을 기준으로 정리해볼 만합니다.",
        ]

    if feature:
        pool += [
            f"매물 특징으로는 {feature} 부분을 함께 참고하시면 좋습니다.",
            f"현장 확인 전에는 {feature} 내용을 먼저 체크해보시면 도움이 됩니다.",
        ]

    if address:
        pool += [
            "소재지 기준으로 주변 생활권과 이동 동선을 함께 확인해보시는 것을 추천드립니다.",
            "주소지를 기준으로 주변 편의시설과 교통 흐름을 함께 비교해보시면 좋습니다.",
        ]

    return "\n".join(pick_many(pool, 4))


def build_location_text(detail):
    address = clean_text(detail.get("address") or detail.get("road_address"))
    complex_name = normalize_duplicate_dong_text(
        detail.get("complex_name") or detail.get("article_name")
    )

    pool = [
        "생활권은 실제 거주 만족도에 큰 영향을 주기 때문에 주변 편의시설과 이동 동선을 함께 확인해보시는 것이 좋습니다.",
        "주변 환경은 사진만으로 판단하기 어려운 부분이 있어 방문 시 단지 분위기와 도로 접근성을 함께 보시면 좋습니다.",
        "출퇴근 동선, 장보기, 병원, 학원 등 생활에 필요한 시설과의 거리를 함께 비교해보시면 판단이 쉬워집니다.",
        "단지 주변 분위기와 접근성은 실거주 만족도를 좌우하는 중요한 요소입니다.",
        "입지만 볼 때는 지도상 거리뿐 아니라 실제 이동 동선도 함께 확인하는 것이 좋습니다.",
        "주변 생활 인프라가 잘 맞는지 확인하면 장기 거주 관점에서도 도움이 됩니다.",
    ]

    if address:
        pool += [
            f"소재지는 {address} 기준으로 확인됩니다.",
            f"{address} 생활권을 고려하시는 분들께 참고가 될 수 있는 매물입니다.",
        ]

    if complex_name:
        pool += [
            f"{complex_name} 주변 환경과 단지 분위기를 함께 비교해보시면 좋습니다.",
        ]

    return "\n".join(pick_many(pool, 3))


def build_space_text(detail):
    area_info = clean_text(detail.get("area_info"))
    floor_info = clean_text(detail.get("floor_info"))
    direction = clean_text(detail.get("direction"))

    pool = [
        "공간은 단순 면적보다 실제 동선과 가구 배치가 중요합니다.",
        "거실과 방의 배치, 수납 공간, 주방 동선을 함께 보시면 실제 사용감이 더 잘 보입니다.",
        "사진을 보실 때는 창 위치와 채광, 통풍 흐름을 함께 확인해보시면 좋습니다.",
        "같은 면적이라도 구조에 따라 체감 공간은 달라질 수 있습니다.",
        "실제 방문 시에는 거실 폭, 방 크기, 주방 동선을 중심으로 확인하시는 것을 추천드립니다.",
        "공간 활용도는 가족 구성원 수와 생활 패턴에 따라 다르게 느껴질 수 있습니다.",
        "수납과 동선이 잘 맞는지 확인하면 실제 거주 만족도를 판단하는 데 도움이 됩니다.",
    ]

    if area_info:
        pool += [
            f"면적은 {area_info} 기준으로, 실제 사용할 공간을 중심으로 보시면 좋습니다.",
            f"{area_info} 타입이라 방 구성과 거실 활용도를 함께 체크해보시면 좋습니다.",
        ]

    if floor_info:
        pool += [
            f"층수는 {floor_info} 기준으로 확인되며, 채광과 조망을 함께 비교해볼 수 있습니다.",
        ]

    if direction:
        pool += [
            f"방향은 {direction}으로 확인되며, 시간대별 채광을 함께 확인해보시면 좋습니다.",
        ]

    return "\n".join(pick_many(pool, 4))


def build_price_text_block(detail):
    price_text = clean_text(detail.get("price_text"))
    trade_type = clean_text(detail.get("trade_type"))

    pool = [
        "가격은 현재 시장 흐름과 주변 유사 매물 조건을 함께 비교해보시는 것이 좋습니다.",
        "매물 가격은 층수, 방향, 내부 상태, 입주 가능 시점에 따라 체감 가치가 달라질 수 있습니다.",
        "단순 가격만 보기보다는 조건 대비 만족도를 함께 확인하는 것이 중요합니다.",
        "같은 단지 안에서도 동, 층, 방향에 따라 가격 차이가 발생할 수 있습니다.",
        "예산 범위 안에서 구조와 위치가 잘 맞는지 함께 비교해보시면 좋습니다.",
        "현재 조건이 본인의 자금 계획과 맞는지 확인한 뒤 현장 방문을 잡는 것이 효율적입니다.",
    ]

    if price_text:
        pool += [
            f"현재 가격 조건은 {price_text} 기준으로 확인됩니다.",
            f"{price_text} 조건을 기준으로 주변 매물과 함께 비교해보시면 좋습니다.",
        ]

    if trade_type:
        pool += [
            f"{trade_type} 매물은 조건 변경이 있을 수 있으므로 상담 전 현재 가능 여부를 확인하시는 것이 좋습니다.",
        ]

    return "\n".join(pick_many(pool, 3))


def build_school_text(detail):
    schools = detail.get("schools") or []

    if schools:
        lines = []

        for school in schools[:3]:
            school_name = clean_text(school.get("school_name"))
            school_type = clean_text(school.get("school_type"))
            distance = clean_text(school.get("distance_text") or school.get("distance"))

            if not school_name:
                continue

            label = " ".join([school_type, distance]).strip()

            if label:
                lines.append(f"인근 교육시설로는 {school_name}({label}) 정보를 참고하실 수 있습니다.")
            else:
                lines.append(f"인근 교육시설로는 {school_name} 정보를 참고하실 수 있습니다.")

        if lines:
            return "\n".join(lines)

    pool = [
        "학군과 교육환경은 가족 단위 실거주 수요에서 중요한 체크 포인트입니다.",
        "자녀 계획이 있으시다면 주변 학교와 학원 접근성을 함께 확인해보시면 좋습니다.",
        "교육환경은 실제 생활 동선과 밀접하므로 방문 전 지도 기준으로 한 번 더 확인을 추천드립니다.",
        "학교 배정과 통학 동선은 변동 가능성이 있어 상담 시 별도 확인이 필요합니다.",
    ]

    return "\n".join(pick_many(pool, 2))


def build_realtor_text(detail):
    info = detail.get("realtor_info") or {}
    office_name = clean_text(info.get("office_name"))

    pool = [
        "상담 시에는 현재 매물 가능 여부, 가격 조건, 입주 가능일을 먼저 확인하시면 좋습니다.",
        "방문 전 유선으로 매물 상태와 조건 변동 여부를 확인하시면 더 정확한 안내를 받을 수 있습니다.",
        "사진만으로 판단하기 어려운 부분은 현장 방문을 통해 직접 확인하시는 것이 가장 좋습니다.",
        "실제 매물 여부와 세부 조건은 상담 시점에 다시 확인해드리는 것이 안전합니다.",
    ]

    if office_name:
        pool += [
            f"{office_name}에서 현재 확인 가능한 조건을 기준으로 안내드립니다.",
            f"자세한 상담은 {office_name}을 통해 확인하실 수 있습니다.",
        ]

    return "\n".join(pick_many(pool, 3))


def build_closing_text(detail):
    pool = [
        "관심 있으신 분들은 현장 확인과 함께 자세한 상담을 받아보시길 권해드립니다.",
        "사진과 기본 정보만으로는 판단이 어려운 부분이 있으니 직접 확인해보시는 것을 추천드립니다.",
        "조건이 맞는 매물은 빠르게 변동될 수 있으니 문의 전 현재 가능 여부를 확인해 주세요.",
        "방문 상담을 통해 실제 구조와 주변 분위기를 함께 확인해보시면 좋습니다.",
        "궁금하신 점은 편하게 문의 주시면 현재 확인 가능한 내용 기준으로 안내드리겠습니다.",
        "매물 조건은 변동될 수 있으므로 상담 시점의 최신 정보를 기준으로 확인해 주세요.",
    ]

    return pick_one(pool)


def build_human_blog_context(detail_row):
    intro_text = build_intro_text(detail_row)
    feature_text = build_feature_text(detail_row)
    location_text = build_location_text(detail_row)
    space_text = build_space_text(detail_row)
    price_text_block = build_price_text_block(detail_row)
    school_text = build_school_text(detail_row)
    realtor_text = build_realtor_text(detail_row)
    outro_text = build_closing_text(detail_row)

    return {
        "intro_text": intro_text,
        "feature_text": feature_text,
        "location_text": location_text,
        "space_text": space_text,
        "price_text_block": price_text_block,
        "school_text": school_text,
        "realtor_text": realtor_text,
        "outro_text": outro_text,
    }


def enrich_ai_sections(ai_sections, human_context):
    ai_sections = ai_sections or {}

    mapping = {
        "intro": "intro_text",
        "point": "feature_text",
        "location": "location_text",
        "space": "space_text",
        "price": "price_text_block",
        "school": "school_text",
        "realtor": "realtor_text",
        "closing": "outro_text",
    }

    bad_phrases = [
        "현장에서 확인했을 때 공간감과 구조가 안정적으로 느껴지는 매물입니다",
        "매물을 소개드립니다",
        "충분히 관심 있게 볼 수 있는 매물로 판단됩니다",
    ]

    for key, human_key in mapping.items():
        current = clean_text(ai_sections.get(key))
        replacement = clean_text(human_context.get(human_key))

        if not replacement:
            continue

        if not current:
            ai_sections[key] = replacement
            continue

        if any(phrase in current for phrase in bad_phrases):
            ai_sections[key] = replacement
            continue

        if len(current) < 25:
            ai_sections[key] = replacement

    return ai_sections


def fetch_target_articles(
    conn,
    realtor_id=None,
    article_no=None,
    limit=10
):
    sql = """
        SELECT
            d.*,
            a.realtor_id,
            r.office_name,
            r.representative_name,
            r.license_number,
            r.business_number,
            r.office_phone,
            r.mobile_phone,
            r.naver_realtor_id

        FROM blog_realestate_article_details d

        JOIN blog_realtor_articles a
            ON CONVERT(d.article_no USING utf8mb4)
               COLLATE utf8mb4_unicode_ci
            =
               CONVERT(a.article_no USING utf8mb4)
               COLLATE utf8mb4_unicode_ci

        LEFT JOIN blog_realtors r
            ON a.realtor_id = r.id

        WHERE d.article_no IS NOT NULL
    """

    params = []

    if realtor_id:
        sql += " AND a.realtor_id = %s "
        params.append(int(realtor_id))

    if article_no:
        sql += " AND a.article_no = %s "
        params.append(str(article_no))

    sql += """
        AND CONVERT(d.article_no USING utf8mb4)
            COLLATE utf8mb4_unicode_ci
        NOT IN (
            SELECT article_no
            FROM blog_article_drafts
        )

        ORDER BY d.id DESC
        LIMIT %s
    """

    params.append(int(limit))

    with conn.cursor() as cur:
        cur.execute(sql, params)
        return cur.fetchall()


def fetch_article_images(conn, article_no):
    with conn.cursor() as cur:
        cur.execute("""
            SELECT *
            FROM blog_realestate_article_images
            WHERE article_no = %s
            ORDER BY
                CASE
                    WHEN image_category = 'inside' THEN 1
                    WHEN image_category = 'article' THEN 2
                    WHEN image_category = 'building' THEN 3
                    WHEN image_category = 'floorplan' THEN 4
                    WHEN image_category = 'birdview' THEN 5
                    WHEN image_category = 'realtor' THEN 9
                    ELSE 6
                END,
                sort_order ASC,
                id ASC
        """, (article_no,))

        return cur.fetchall()


def fetch_article_prices(conn, article_no):
    with conn.cursor() as cur:
        cur.execute("""
            SELECT *
            FROM blog_realestate_article_prices
            WHERE article_no = %s
            ORDER BY id ASC
            LIMIT 20
        """, (article_no,))

        return cur.fetchall()


def fetch_article_schools(conn, article_no):
    with conn.cursor() as cur:
        cur.execute("""
            SELECT *
            FROM blog_realestate_article_schools
            WHERE article_no = %s
            ORDER BY id ASC
            LIMIT 20
        """, (article_no,))

        return cur.fetchall()


def save_draft(
    conn,
    realtor_id,
    article_no,
    draft_data,
    ai_sections,
    source_json,
):
    draft_title = draft_data.get("draft_title", "")[:255]
    layout_type = draft_data.get("layout_type", "default")

    draft_html = draft_data.get("draft_html", "")
    clipboard_html = draft_data.get("clipboard_html", "")
    plain_text = draft_data.get("plain_text", "")

    with conn.cursor() as cur:
        cur.execute("""
            INSERT INTO blog_article_drafts
            (
                realtor_id,
                article_no,
                draft_title,
                layout_type,
                draft_html,
                clipboard_html,
                plain_text,
                ai_summary,
                ai_sections,
                source_json,
                status,
                created_at,
                updated_at
            )
            VALUES
            (
                %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
                'ready',
                NOW(),
                NOW()
            )

            ON DUPLICATE KEY UPDATE
                draft_title = VALUES(draft_title),
                layout_type = VALUES(layout_type),
                draft_html = VALUES(draft_html),
                clipboard_html = VALUES(clipboard_html),
                plain_text = VALUES(plain_text),
                ai_summary = VALUES(ai_summary),
                ai_sections = VALUES(ai_sections),
                source_json = VALUES(source_json),
                status = 'ready',
                updated_at = NOW()
        """, (
            realtor_id,
            article_no,
            draft_title,
            layout_type,
            draft_html,
            clipboard_html,
            plain_text,
            ai_sections.get("intro", "")[:1000],
            json.dumps(ai_sections, ensure_ascii=False, default=json_default),
            json.dumps(source_json, ensure_ascii=False, default=json_default),
        ))

    conn.commit()


def process_article(conn, detail_row):
    article_no = str(detail_row.get("article_no"))
    realtor_id = detail_row.get("realtor_id") or 0

    print("-" * 80)
    print(f"[DRAFT START] {article_no}")

    images = fetch_article_images(conn, article_no)
    prices = fetch_article_prices(conn, article_no)
    schools = fetch_article_schools(conn, article_no)
    feature_comment = build_feature_comment_block(
        detail_row
    )

    if not images:
        raise Exception("draft images empty")

    detail_row["realtor_info"] = {
        "office_name": detail_row.get("office_name", ""),
        "representative_name": detail_row.get("representative_name", ""),
        "license_number": detail_row.get("license_number", ""),
        "business_number": detail_row.get("business_number", ""),
        "office_phone": detail_row.get("office_phone", ""),
        "mobile_phone": detail_row.get("mobile_phone", ""),
        "naver_realtor_id": detail_row.get("naver_realtor_id", ""),
    }

    detail_row["market_prices"] = prices
    detail_row["schools"] = schools

    human_context = build_human_blog_context(detail_row)

    ai_sections = generate_ai_sections({
        **detail_row,
        **human_context,
    })

    ai_sections = enrich_ai_sections(
        ai_sections,
        human_context,
    )

    layout_type = random.choice([
        "story_first",
        "photo_first",
        "summary_first",
        "gallery_story",
        "location_focus",
        "recommendation_focus",
        "magazine_style",
        "interview_style",
        "checklist_style",
        "quiet_luxury",
        "short_review_style",
        "wide_visual",
        "photo_grid",
        "minimal_modern",
        "storytelling",
        "local_life",
        "broker_expert",
        "premium_report",
    ])

    extra_images = get_extra_images_if_needed(
        conn=conn,
        realtor_id=realtor_id,
        article_no=article_no,
        images=images,
    )

    print(
        f"[EXTRA IMAGES] "
        f"original={len(images)}, "
        f"extra={len(extra_images)}"
    )

    draft_data = build_blog_html(
        detail=detail_row,
        images=images,
        ai_sections=ai_sections,
        layout_type=layout_type,
        extra_images=extra_images,
    )

    if not draft_data:
        raise Exception("draft_data empty")

    source_json = {
        "detail": detail_row,
        "images": images,
        "prices": prices,
        "schools": schools,
        "human_context": human_context,
        "feature_comment": feature_comment,
    }

    save_draft(
        conn=conn,
        realtor_id=realtor_id,
        article_no=article_no,
        draft_data=draft_data,
        ai_sections=ai_sections,
        source_json=source_json,
    )

    with conn.cursor() as cur:
        cur.execute("""
            SELECT id
            FROM blog_article_drafts
            WHERE article_no = %s
            LIMIT 1
        """, (article_no,))

        saved = cur.fetchone()

    if not saved:
        raise Exception(f"draft save failed: {article_no}")

    print(f"[DRAFT SAVED] {article_no}")
    print(f"[LAYOUT] {layout_type}")
    print(f"[IMAGES] {len(images)}")
    print(f"[PRICES] {len(prices)}")
    print(f"[SCHOOLS] {len(schools)}")


def main():
    parser = argparse.ArgumentParser()

    parser.add_argument("--realtor-id", type=int, default=None)
    parser.add_argument("--article-no", type=str, default=None)
    parser.add_argument("--limit", type=int, default=9999)

    args = parser.parse_args()

    conn = get_conn()

    try:
        print("=" * 80)
        print("[START] generate_blog_drafts")
        print("TIME:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        print("=" * 80)

        articles = fetch_target_articles(
            conn=conn,
            realtor_id=args.realtor_id,
            article_no=args.article_no,
            limit=args.limit,
        )

        print(f"[TARGET ARTICLES] {len(articles)}")

        for row in articles:
            process_article(conn, row)

        print("=" * 80)
        print("[DONE] generate_blog_drafts")
        print("=" * 80)

    finally:
        conn.close()


if __name__ == "__main__":
    main()