"""
Content Post Queue + Calendar Scheduler
Ported & adapted từ BrightBean Studio apps/calendar/services.py
Logic: define PostingSlots theo weekday → auto-assign datetime cho queued content
"""

import json
import logging
import os
from datetime import datetime, time, timedelta, timezone

logger = logging.getLogger(__name__)

QUEUE_FILE = os.path.join(
    os.path.dirname(os.path.abspath(__file__)), "..", "..", "data", "post_queue.json"
)
SLOTS_FILE = os.path.join(
    os.path.dirname(os.path.abspath(__file__)), "..", "..", "data", "posting_slots.json"
)

# ─── Default slots (từ BrightBean — non-round times để tránh shadow ban) ────
# Canifa: Đăng T2/T3/T4/T5 vào giờ "vàng" sáng
DEFAULT_SLOTS = [
    {"day": 0, "hour": 9,  "minute": 24, "label": "Thứ 2 sáng"},   # Monday
    {"day": 0, "hour": 11, "minute": 10, "label": "Thứ 2 trưa"},
    {"day": 1, "hour": 9,  "minute": 55, "label": "Thứ 3 sáng"},   # Tuesday
    {"day": 2, "hour": 9,  "minute": 30, "label": "Thứ 4 sáng"},   # Wednesday
    {"day": 2, "hour": 11, "minute": 32, "label": "Thứ 4 trưa"},
    {"day": 3, "hour": 9,  "minute": 38, "label": "Thứ 5 sáng"},   # Thursday
    {"day": 4, "hour": 10, "minute": 17, "label": "Thứ 6 sáng"},   # Friday
    {"day": 4, "hour": 14, "minute": 0,  "label": "Thứ 6 chiều"},
    {"day": 5, "hour": 10, "minute": 0,  "label": "Thứ 7 sáng"},   # Saturday
]


# ─── Storage ─────────────────────────────────────────────────────────────────

def _ensure_dir():
    for f in [QUEUE_FILE, SLOTS_FILE]:
        os.makedirs(os.path.dirname(f), exist_ok=True)


def _load_queue() -> list[dict]:
    _ensure_dir()
    if not os.path.exists(QUEUE_FILE):
        return []
    try:
        with open(QUEUE_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return []


def _save_queue(data: list[dict]):
    _ensure_dir()
    with open(QUEUE_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2, default=str)


def _load_slots() -> list[dict]:
    _ensure_dir()
    if not os.path.exists(SLOTS_FILE):
        _save_slots(DEFAULT_SLOTS)
        return DEFAULT_SLOTS
    try:
        with open(SLOTS_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return DEFAULT_SLOTS


def _save_slots(data: list[dict]):
    _ensure_dir()
    with open(SLOTS_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2, default=str)


# ─── Core slot logic (from BrightBean calendar/services.py) ─────────────────

def _next_slot_datetimes(after_dt: datetime, count: int = 20) -> list[datetime]:
    """
    Tính toán N thời điểm publish tiếp theo dựa trên PostingSlots.
    Walk 60 ngày tới để tìm đủ slots.
    """
    slots = _load_slots()
    if not slots:
        return []

    results = []
    current_date = after_dt.date()

    for day_offset in range(60):
        check_date = current_date + timedelta(days=day_offset)
        weekday = check_date.weekday()  # 0=Monday

        for slot in slots:
            if slot.get("day") != weekday:
                continue

            slot_dt = datetime.combine(
                check_date,
                time(slot.get("hour", 9), slot.get("minute", 0)),
                tzinfo=timezone.utc,
            )

            if slot_dt <= after_dt:
                continue

            results.append(slot_dt)
            if len(results) >= count:
                return results

    return results


def assign_queue_slots() -> list[dict]:
    """
    Recalculate scheduled_at cho tất cả queued content.
    Gọi sau mỗi khi add/remove/reorder queue.
    """
    queue = _load_queue()
    if not queue:
        return []

    now = datetime.now(timezone.utc)
    slot_times = _next_slot_datetimes(now, count=len(queue) + 5)

    for idx, entry in enumerate(queue):
        if idx < len(slot_times):
            entry["scheduled_at"] = slot_times[idx].isoformat()
        else:
            entry["scheduled_at"] = None

    _save_queue(queue)
    return queue


def add_to_queue(content_id: str, priority: bool = False) -> list[dict]:
    """
    Thêm content vào queue.
    priority=True → đẩy lên đầu (cho campaign quan trọng).
    """
    queue = _load_queue()

    # Remove nếu đã có
    queue = [e for e in queue if e.get("content_id") != content_id]

    entry = {
        "content_id": content_id,
        "position":   0,
        "added_at":   datetime.now(timezone.utc).isoformat(),
        "scheduled_at": None,
    }

    if priority:
        queue.insert(0, entry)
    else:
        queue.append(entry)

    # Update positions
    for i, e in enumerate(queue):
        e["position"] = i

    _save_queue(queue)
    return assign_queue_slots()


def remove_from_queue(content_id: str) -> list[dict]:
    """Xoá content khỏi queue."""
    queue = _load_queue()
    queue = [e for e in queue if e.get("content_id") != content_id]
    for i, e in enumerate(queue):
        e["position"] = i
    _save_queue(queue)
    return assign_queue_slots()


def reorder_queue(ordered_content_ids: list[str]) -> list[dict]:
    """Reorder queue theo danh sách content_id (drag-drop)."""
    queue = _load_queue()
    queue_map = {e["content_id"]: e for e in queue}

    new_queue = []
    for idx, cid in enumerate(ordered_content_ids):
        if cid in queue_map:
            entry = queue_map[cid]
            entry["position"] = idx
            new_queue.append(entry)

    # Append entries không có trong ordered list
    existing_ids = set(ordered_content_ids)
    for e in queue:
        if e["content_id"] not in existing_ids:
            new_queue.append(e)

    _save_queue(new_queue)
    return assign_queue_slots()


def get_queue() -> list[dict]:
    """Lấy queue hiện tại với thông tin content đính kèm."""
    queue = _load_queue()
    # Enrich với content data
    try:
        from common.social.approval_gate import get_content
        enriched = []
        for entry in queue:
            content = get_content(entry["content_id"])
            enriched.append({**entry, "content": content})
        return enriched
    except Exception:
        return queue


def get_due_for_publish(now: datetime | None = None) -> list[dict]:
    """
    Lấy danh sách queue entries đã đến giờ publish.
    Dùng bởi PublishEngine để biết publish cái gì.
    """
    if now is None:
        now = datetime.now(timezone.utc)
    queue = _load_queue()
    due = []
    for entry in queue:
        scheduled = entry.get("scheduled_at")
        if not scheduled:
            continue
        scheduled_dt = datetime.fromisoformat(scheduled)
        if scheduled_dt <= now:
            due.append(entry)
    return due


# ─── Slots management ────────────────────────────────────────────────────────

def get_slots() -> list[dict]:
    return _load_slots()


def save_slots(slots: list[dict]) -> list[dict]:
    """Save custom posting slots."""
    _save_slots(slots)
    assign_queue_slots()  # Recalculate queue
    return slots


def reset_slots_to_default() -> list[dict]:
    _save_slots(DEFAULT_SLOTS)
    assign_queue_slots()
    return DEFAULT_SLOTS


# ─── Calendar view ────────────────────────────────────────────────────────────

def get_calendar_week(week_offset: int = 0) -> dict:
    """
    Lấy data cho calendar view theo tuần.
    week_offset=0 → tuần này, 1 → tuần sau, -1 → tuần trước.
    """
    today = datetime.now(timezone.utc)
    monday = today - timedelta(days=today.weekday()) + timedelta(weeks=week_offset)

    days = []
    queue = _load_queue()
    content_by_date: dict[str, list] = {}

    for entry in queue:
        scheduled = entry.get("scheduled_at")
        if scheduled:
            dt = datetime.fromisoformat(scheduled)
            date_key = dt.strftime("%Y-%m-%d")
            content_by_date.setdefault(date_key, []).append(entry)

    day_names = ["Thứ 2", "Thứ 3", "Thứ 4", "Thứ 5", "Thứ 6", "Thứ 7", "CN"]
    for i in range(7):
        day = monday + timedelta(days=i)
        date_key = day.strftime("%Y-%m-%d")
        days.append({
            "date":      date_key,
            "day_name":  day_names[i],
            "is_today":  date_key == today.strftime("%Y-%m-%d"),
            "entries":   content_by_date.get(date_key, []),
        })

    return {
        "week_start": monday.strftime("%Y-%m-%d"),
        "week_offset": week_offset,
        "days": days,
    }
