import asyncio
import json
import logging
import sys
import os
import httpx

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from common.cache import redis_cache
from common.pool_wrapper import get_pooled_connection_compat
from api.bulk_ops_route import _render_description_text, _call_codex

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", datefmt="%y-%m-%d %H:%M:%S")
logger = logging.getLogger("size_guide_worker")

PG_TABLE = "dashboard_canifa.ultra_descriptions"
SIZE_GUIDE_TABLE = "dashboard_canifa.product_size_guide"
BATCH_CONCURRENCY = 5

async def handle_size_guide_job(redis, job_data, client, conn):
    job_id = job_data.get("job_id")
    codes = job_data.get("codes", [])
    instruction = job_data.get("instruction", "")
    target_field = "huong_dan_size"
    auto_mode = (instruction == "AUTO_ENRICH_FROM_SIZEGUIDE")
    
    if not job_id or not codes: return
    logger.info(f"🚀 Found Size Guide Job {job_id} for {len(codes)} SKUs (auto_mode={auto_mode})")

    progress_key = f"size_guide:progress:{job_id}"
    
    done_count = err_count = 0
    sem = asyncio.Semaphore(BATCH_CONCURRENCY)

    async def _worker(code: str):
        nonlocal done_count, err_count
        if not code: return
        async with sem:
            cur = None
            try:
                cur = conn.cursor()

                if auto_mode:
                    # JOIN with product_size_guide to get HTML sizeguide
                    cur.execute(f"""
                        SELECT u.product_name, u.product_line, u.description_data, u.size_scale,
                               s.sizeguide_content, s.age_by_product, s.gender_by_product
                        FROM {PG_TABLE} u
                        LEFT JOIN {SIZE_GUIDE_TABLE} s ON u.internal_ref_code = s.internal_ref_code
                        WHERE u.internal_ref_code = %s
                    """, (code,))
                    row = cur.fetchone()
                    if not row:
                        err_count += 1
                        return
                    name, p_line, desc_data, size_scale, sizeguide_html, age, gender = row
                else:
                    cur.execute(f"SELECT product_name, product_line, description_data FROM {PG_TABLE} WHERE internal_ref_code = %s", (code,))
                    row = cur.fetchone()
                    if not row:
                        err_count += 1
                        return
                    name, p_line, desc_data = row
                    sizeguide_html = None
                    age = gender = None
                    size_scale = None
                
                if isinstance(desc_data, str):
                    try: desc_data = json.loads(desc_data)
                    except: desc_data = {}
                elif desc_data is None:
                    desc_data = {}
                
                context_fields = {
                    "ten_san_pham": desc_data.get("ten_san_pham", name or ""),
                    "phong_cach": desc_data.get("phong_cach", ""),
                    "chat_lieu": desc_data.get("chat_lieu", ""),
                    "gioi_tinh": desc_data.get("gioi_tinh", gender or ""),
                    "mua": desc_data.get("mua", ""),
                    "do_tuoi": desc_data.get("do_tuoi", age or ""),
                    "product_line": p_line or "",
                }
                if auto_mode and size_scale:
                    context_fields["size_scale"] = json.dumps(size_scale)
                context_str = "\n".join(f"- {k}: {v}" for k, v in context_fields.items() if v)

                if auto_mode and sizeguide_html:
                    # Use the enhanced prompt with HTML sizeguide
                    prompt = f"""Bạn là Stylist thời trang chuyên nghiệp của Canifa. Dựa trên thông tin sản phẩm và Bảng thông số size HTML bên dưới, hãy sinh hướng dẫn chọn size tự nhiên, chính xác.

THÔNG TIN SẢN PHẨM:
{context_str}

BẢNG SIZE HTML (Parse từ Magento):
{sizeguide_html[:3000]}

QUY TẮC BẮT BUỘC:
1. BẢNG THÔNG SỐ: Liệt kê các size có sẵn dạng bảng dễ đọc (Size, Chiều cao, Cân nặng, Vòng ngực/mông nếu có).
2. HƯỚNG DẪN CHỌN SIZE THEO CHIỀU CAO: Ví dụ cụ thể (VD: Bé cao 115cm, nặng 22kg → nên chọn Size 110).
3. GỢI Ý MẶC SIZE — PHẦN NÀY RẤT QUAN TRỌNG:
   Dựa vào LOẠI SẢN PHẨM CỤ THỂ (áo phông, quần jean, váy, áo khoác...) + chất liệu + phong cách, đưa ra lời khuyên:
   - Nên chọn đúng size hay tăng/giảm size? Tại sao?
   - VD: "Áo phông trẻ em nên chọn rộng hơn 1 size để bé thoải mái vận động"
   - VD: "Quần jean slim fit nên chọn đúng size, nếu thích thoải mái hơn thì tăng 1 size"
   - VD: "Áo khoác gió nên tăng 1 size nếu muốn layer áo bên trong"
   - Chất liệu co giãn (cotton, thun) → có thể chọn đúng size
   - Chất liệu ít co giãn (kaki, denim) → nên tăng 1 size
4. LƯU Ý: Kèm lưu ý nhỏ cuối (VD: Số đo có thể chênh 1-2cm tùy co giãn vải).
- FORMAT: Dùng bullet point rõ ràng dễ đọc.
- Trả về chỉ nội dung text, KHÔNG giải thích thêm."""
                else:
                    # Original prompt with manual instruction
                    prompt = f"""Bạn là Stylist thời trang chuyên nghiệp của Canifa. Dựa trên thông tin sản phẩm và Bảng thông số size (được cung cấp trong YÊU CẦU), hãy sinh ra đoạn văn bản Hướng dẫn chọn size tự nhiên, có tâm và chính xác.

THÔNG TIN SẢN PHẨM:
{context_str}

YÊU CẦU CỦA ADMIN (Chứa bảng size thô / các tips lưu ý):
{instruction}

QUY TẮC BẮT BUỘC ('Hướng dẫn chọn size'):
- Tạo thành VĂN BẢN (Text) bao gồm 2 phần: (1) Bảng thông số dễ đọc và (2) Lời khuyên chọn size chi tiết.
- Sử dụng đúng thông tin size từ YÊU CẦU (KHÔNG bịa số đo).
- Trả về CHỈ nội dung text, KHÔNG có lời chào hỏi đầu đuôi.
"""

                messages = [
                    {"role": "system", "content": "Bạn là AI phụ trách nội dung sản phẩm thời trang Canifa."},
                    {"role": "user", "content": prompt},
                ]
                
                ai_output = await _call_codex(messages, max_tokens=1500, temperature=0.7)
                new_value = ai_output.strip().strip('"').strip("'")
                
                desc_data[target_field] = new_value
                new_clean = _render_description_text(desc_data, name or "")
                
                cur.execute(
                    f"UPDATE {PG_TABLE} SET description_data = %s::jsonb, clean_description = %s, updated_at = NOW() WHERE internal_ref_code = %s",
                    (json.dumps(desc_data, ensure_ascii=False), new_clean, code)
                )
                conn.commit()
                
            except Exception as e:
                logger.error(f"❌ Size Guide gen failed for {code}: {e}")
                err_count += 1
                if conn: conn.rollback()
            finally:
                if cur: cur.close()
                done_count += 1
                if done_count % 5 == 0 or done_count == len(codes):
                    await redis.hset(progress_key, mapping={"done": done_count, "errors": err_count, "current_code": code})

    await asyncio.gather(*[_worker(c) for c in codes])
    await redis.hset(progress_key, "is_running", "false")
    logger.info(f"🎉 Size Guide Job {job_id} finished. Total: {len(codes)}, Errors: {err_count}")


async def main():
    await redis_cache.initialize()
    redis = redis_cache.get_client()
    if not redis:
        logger.error("Redis client is not available.")
        sys.exit(1)

    logger.info("👷 Size Guide Worker started. Waiting for jobs on 'size_guide:queue'...")
    
    timeout = httpx.Timeout(45.0)
    async with httpx.AsyncClient(timeout=timeout) as client:
        # One DB connection pool for the worker
        while True:
            try:
                item = await redis.brpop("size_guide:queue", timeout=2)
                if not item: continue
                
                _, payload = item
                job_data = json.loads(payload)
                
                progress_key = f"size_guide:progress:{job_data.get('job_id')}"
                await redis.set("size_guide:progress:latest_job", job_data.get('job_id'))
                await redis.hset(progress_key, mapping={
                    "is_running": "true",
                    "total": len(job_data.get("codes", [])),
                    "done": 0,
                    "errors": 0,
                })
                # Giữ trạng thái trong 1 tiếng
                await redis.expire(progress_key, 3600)

                conn = get_pooled_connection_compat()
                try:
                    await handle_size_guide_job(redis, job_data, client, conn)
                finally:
                    if conn: conn.close()

            except Exception as e:
                logger.error(f"Worker loop error: {e}")
                await asyncio.sleep(5)

if __name__ == "__main__":
    if sys.platform == 'win32':
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    asyncio.run(main())
