# -*- coding: utf-8 -*-

import json
import random
import requests
import re

from config import (
    ENABLE_OLLAMA,
    OLLAMA_API_URL,
    OLLAMA_MODEL,
)


def detect_property_class(article_detail):
    code = str(
        article_detail.get("_raw_article_type_code")
        or article_detail.get("real_estate_type_code")
        or ""
    ).strip().upper()
    name = str(
        article_detail.get("real_estate_type")
        or article_detail.get("real_estate_type_name")
        or ""
    ).strip()

    if code in {"SG", "SMS"} or any(x in name for x in ("상가", "점포", "사무실", "업무시설")):
        return "commercial"
    if code in {"GJCG", "GM", "CW"} or any(x in name for x in ("공장", "창고", "지식산업센터")):
        return "factory_warehouse"
    if code in {"TJ", "LAND", "TOJI", "E03"} or name in {
        "토지", "대", "전", "답", "임야", "대지", "잡종지", "공장용지", "창고용지",
    }:
        return "land"
    return "residential"


def property_writing_rules(article_detail):
    cls = detect_property_class(article_detail)
    if cls == "commercial":
        return """
- 상가·업무용 관점으로만 작성한다.
- 상권, 유동인구, 배후수요, 가시성, 고객 접근, 층·전면·주차, 업종 적합성, 관리비·권리금을 다룬다.
- 가족 구성원, 실거주, 거실·방·주방, 학군, 채광 중심의 주거 문구를 쓰지 않는다.
"""
    if cls == "factory_warehouse":
        return """
- 공장·창고 관점으로만 작성한다.
- 층고, 전력, 바닥하중, 차량 진입, 하역, 진입도로, 설비, 공장등록·용도를 다룬다.
- 가족 구성원, 실거주, 거실·방·주방, 학군, 생활편의 중심의 주거 문구를 쓰지 않는다.
"""
    if cls == "land":
        return """
- 토지·대지 관점으로만 작성한다.
- 지목, 용도지역, 면적, 형상, 접도, 진입로, 건폐율·용적률과 개발 제한을 원문 범위에서 다룬다.
- 층수, 방향, 실내, 거실·방·주방, 학군, 실거주 문구를 쓰지 않는다.
"""
    return """
- 주거형 매물 관점으로 작성한다.
- 구조, 동선, 채광, 수납, 생활권과 실제 제공된 학군 정보를 중심으로 작성한다.
"""


def build_property_prompt(article_detail):

    article_name = article_detail.get("article_title") or ""
    article_desc = article_detail.get("article_desc") or ""
    trade_type = article_detail.get("trade_type", "")
    real_estate_type = article_detail.get("real_estate_type", "")
    price_text = article_detail.get("price_text", "")
    floor_info = article_detail.get("floor_info", "")
    area_info = article_detail.get("area_info", "")
    address = article_detail.get("address", "")
    road_address = article_detail.get("road_address", "")
    parking_info = article_detail.get("parking_info", "")
    direction = article_detail.get("direction", "")
    building_usage = article_detail.get("building_usage") or ""
    writing_rules = property_writing_rules(article_detail)

    realtor_info = article_detail.get("realtor_info", {})
    prices = article_detail.get("market_prices", [])
    schools = article_detail.get("schools", [])

    price_lines = []

    for p in prices[:8]:

        line = []

        if p.get("deal_type"):
            line.append(str(p.get("deal_type")))

        if p.get("price_text"):
            line.append(str(p.get("price_text")))

        if p.get("floor_info"):
            line.append(str(p.get("floor_info")))

        if line:
            price_lines.append(" / ".join(line))

    school_lines = []

    for s in schools[:8]:

        name = s.get("school_name") or ""
        dist = s.get("distance") or ""

        if name:
            school_lines.append(f"{name} {dist}")

    feeling_style = random.choice([
        "차분하고 신뢰감 있는 중개사 말투",
        "실제 방문한 느낌의 현장 설명 스타일",
        "고급스럽고 자연스러운 부동산 매거진 스타일",
        "지역 중개 전문가 느낌",
        "실거주 관점 설명 스타일",
        "프리미엄 부동산 에디터 스타일",
        "현장 중심 리뷰 스타일",
        "고객 상담 기반 설명 스타일",
    ])

    return f"""
너는 네이버 부동산 전문 블로그 작가다.

절대 AI처럼 쓰지 말 것.

매우 중요:
- 실제 공인중개사가 현장 방문 후 작성한 느낌
- 같은 표현 반복 금지
- 문장 길이 다양하게
- 기계적 나열 금지
- 생활 관점 설명 포함
- 투자 관점 설명 포함
- 실거주 관점 설명 포함
- 현장 분위기 표현
- 공간감 표현
- 채광/동선/주변 느낌 표현
- 과장 광고 금지
- 없는 정보 상상 금지
- 자연스러운 블로그 문체
- 사람 냄새 나는 문장
- 문단 간 연결감 만들 것

[매물종류별 작성 규칙]
{writing_rules}

문체 스타일:
{feeling_style}

매물 정보:

[매물유형 확정 규칙 - 매우 중요]
- 부동산유형은 "{real_estate_type}"로 확정한다.
- 부동산유형을 절대 다른 유형으로 바꾸거나 추론하지 마라.
- 부동산유형이 아파트/오피스텔/빌라/주택/상가/사무실이면 토지 매물처럼 작성하지 마라.
- 아파트/오피스텔/빌라/주택/상가/사무실 문서에서는 다음 표현을 절대 쓰지 마라:
  토지 개요, 토지 핵심 정보, 토지 확인 포인트, 토지 매물, 토지면적, 지목, 접도, 진입로, 개발 가능성, 건축허가, 토지이용계획, 임야, 대지
- 주소에 산/전/답/대전 같은 글자가 들어가도 매물유형을 토지로 판단하지 마라.
- 제공된 매물정보에 없는 장점, 투자성, 개발 가능성, 학군, 교통 정보는 만들지 마라.
- 정보가 부족하면 짧고 정확하게 작성하라.

[기본정보]
- 매물명: {article_name}
- 설명: {article_desc}
- 거래유형: {trade_type}
- 부동산유형: {real_estate_type}
- 가격: {price_text}
- 층수: {floor_info}
- 면적: {area_info}
- 주소: {address}
- 도로명주소: {road_address}
- 주차: {parking_info}
- 방향: {direction}
- 용도: {building_usage}

[중개사정보]
- 중개사무소: {realtor_info.get("office_name", "")}
- 대표자: {realtor_info.get("representative_name", "")}

[실거래 및 시세]
{chr(10).join(price_lines)}

[학군정보]
{chr(10).join(school_lines)}

반드시 아래 JSON 형식만 출력해라.

{{
  "intro": "도입 문단 (5~8문장)",
  "location": "입지 및 생활권 설명 (6~10문장)",
  "space": "실내 구조 및 공간 설명 (6~10문장)",
  "point": "추천 포인트 및 장점 설명 (5~8문장)",
  "price": "가격 및 실거래 흐름 해석 (5~8문장)",
  "school": "학군 및 생활환경 설명 (4~6문장)",
  "investment": "투자 관점 설명 (4~6문장)",
  "caution": "확인 포인트 및 체크사항 (3~5문장)",
  "realtor": "중개사 안내 및 상담 유도 (3~5문장)",
  "closing": "마무리 문단 (4~6문장)"
}}
""".strip()


def fallback_sections(article_detail):

    title = article_detail.get("article_title") or "추천 매물"
    cls = detect_property_class(article_detail)

    if cls == "commercial":
        return {
            "intro": f"{title} 상가·업무용 매물의 현재 조건을 안내드립니다.",
            "location": "상권 흐름, 유동인구, 배후수요와 고객 접근 동선을 현장에서 확인해 주세요.",
            "space": "전용면적, 층 위치, 출입구, 전면 노출과 업종에 필요한 설비 조건을 확인해 주세요.",
            "point": "가시성, 접근성, 주차 여건과 희망 업종의 적합성을 함께 검토하는 것이 중요합니다.",
            "price": "보증금·임대료·관리비와 권리금 유무는 계약 전 최신 조건을 확인해 주세요.",
            "school": "",
            "investment": "상권과 배후수요는 현장 조사 및 객관적인 자료와 함께 판단해 주세요.",
            "caution": "건축물 용도, 업종 제한, 관리규약과 시설물 상태를 확인해 주세요.",
            "realtor": "방문 전 현재 매물 가능 여부와 세부 조건을 중개사무소에 확인해 주세요.",
            "closing": "희망 업종과 운영 조건을 정리한 뒤 현장에서 세부 사항을 확인해 주세요.",
        }
    if cls == "factory_warehouse":
        return {
            "intro": f"{title} 공장·창고 매물의 현재 조건을 안내드립니다.",
            "location": "대형차 진입, 주요 도로 연결, 하역 동선과 주변 민원 가능성을 확인해 주세요.",
            "space": "층고, 전력, 바닥하중, 기둥 간격과 기존 설비 상태를 현장에서 확인해야 합니다.",
            "point": "사업 용도에 필요한 차량 접근성과 설비 설치 가능 여부가 핵심 확인사항입니다.",
            "price": "임대·매매 조건과 전력 증설, 설비 이전, 원상복구 비용을 함께 검토해 주세요.",
            "school": "",
            "investment": "사업 운영비와 시설 보완 비용을 객관적인 자료에 따라 검토해 주세요.",
            "caution": "건축물 용도, 공장등록, 소방 기준과 진입도로 조건을 확인해 주세요.",
            "realtor": "방문 전 현재 매물 가능 여부와 세부 조건을 중개사무소에 확인해 주세요.",
            "closing": "필요 설비와 물류 동선을 기준으로 현장을 확인해 주세요.",
        }
    if cls == "land":
        return {
            "intro": f"{title} 토지·대지 매물의 현재 조건을 안내드립니다.",
            "location": "현황도로, 진입 조건과 주변 토지 이용 상태를 확인해 주세요.",
            "space": "",
            "point": "지목, 용도지역·지구, 형상과 도로 접면을 원문 자료 기준으로 확인해야 합니다.",
            "price": "가격은 접도, 개발 제한과 기반시설 조건을 함께 비교해야 합니다.",
            "school": "",
            "investment": "개발 가능성은 관계 기관 확인 전 확정적으로 표현할 수 없습니다.",
            "caution": "토지이용계획확인서, 지적도, 등기사항과 허가 가능 여부를 확인해 주세요.",
            "realtor": "방문 전 현재 매물 가능 여부와 세부 조건을 중개사무소에 확인해 주세요.",
            "closing": "공부와 현황을 함께 확인한 뒤 신중하게 검토해 주세요.",
        }

    return {
        "intro": f"{title} 매물을 소개드립니다. 현장에서 확인했을 때 공간감과 구조가 안정적으로 느껴지는 매물입니다.",
        "location": "주변 생활 인프라와 이동 동선을 함께 고려해보면 실거주 관점에서도 검토해볼 수 있는 위치입니다.",
        "space": "실내 구조와 채광 방향 등을 함께 확인해보면 공간 활용 측면에서도 장점이 있습니다.",
        "point": "현재 조건 기준으로 비교해보면 충분히 관심 있게 볼 수 있는 매물로 판단됩니다.",
        "price": "가격 조건 역시 최근 시장 흐름과 함께 비교해보며 검토하시면 좋습니다.",
        "school": "생활권과 주변 교육환경도 함께 체크해보시면 좋겠습니다.",
        "investment": "향후 시장 흐름과 입지 조건까지 함께 고려해보며 검토하시면 좋겠습니다.",
        "caution": "실제 계약 전에는 현장 확인과 함께 세부 조건을 다시 체크해보시는 것을 추천드립니다.",
        "realtor": "자세한 상담은 등록 중개사무소를 통해 확인 가능합니다.",
        "closing": "관심 있으신 분들은 직접 현장 확인과 함께 자세한 상담을 받아보시길 추천드립니다.",
    }



def contains_forbidden_property_mismatch(article_detail, sections):
    real_estate_type = str(article_detail.get('real_estate_type') or '').strip()
    joined = ' '.join(str(v or '') for v in (sections or {}).values())

    building_types = ['아파트', '오피스텔', '빌라', '연립', '다세대', '주택', '상가', '사무실']
    land_forbidden_words = [
        '토지 개요',
        '토지 핵심',
        '토지 확인',
        '토지 매물',
        '토지면적',
        '지목',
        '접도',
        '진입로',
        '개발 가능성',
        '건축허가',
        '토지이용계획',
        '임야',
        '대지',
    ]

    if any(t in real_estate_type for t in building_types):
        if any(word in joined for word in land_forbidden_words):
            return True

    cls = detect_property_class(article_detail)
    non_residential_forbidden = [
        "가족 구성원", "실거주", "거실", "방 배치", "주방 동선",
        "수납", "학군", "교육환경", "채광과 개방감",
    ]
    if cls != "residential" and any(word in joined for word in non_residential_forbidden):
        return True

    return False

def generate_ai_sections(article_detail):

    if not ENABLE_OLLAMA:
        return fallback_sections(article_detail)

    prompt = build_property_prompt(article_detail)

    try:

        res = requests.post(
            OLLAMA_API_URL,
            json={
                "model": OLLAMA_MODEL,
                "prompt": prompt,
                "stream": False,
                "options": {
                    "temperature": 0.92,
                    "top_p": 0.95,
                    "repeat_penalty": 1.18,
                    "num_predict": 1800,
                }
            },
            timeout=300
        )

        if res.status_code != 200:
            return fallback_sections(article_detail)

        data = res.json()

        text = data.get("response", "").strip()

        if not text:
            return fallback_sections(article_detail)

        start = text.find("{")
        end = text.rfind("}")

        if start == -1 or end == -1:
            return fallback_sections(article_detail)

        parsed = json.loads(text[start:end + 1])

        sections = {
            "intro": parsed.get("intro", ""),
            "location": parsed.get("location", ""),
            "space": parsed.get("space", ""),
            "point": parsed.get("point", ""),
            "price": parsed.get("price", ""),
            "school": parsed.get("school", ""),
            "investment": parsed.get("investment", ""),
            "caution": parsed.get("caution", ""),
            "realtor": parsed.get("realtor", ""),
            "closing": parsed.get("closing", ""),
        }

        if contains_forbidden_property_mismatch(article_detail, sections):
            print("[OLLAMA PROPERTY MISMATCH BLOCKED]", article_detail.get("article_title"), article_detail.get("real_estate_type"))
            return fallback_sections(article_detail)

        return sections

    except Exception as e:

        print("[OLLAMA ERROR]", str(e))

        return fallback_sections(article_detail)
