"""SQLite CRUD helpers for the Communication Strategist (daily action plans)."""

from __future__ import annotations

import json
import time
import uuid
from datetime import datetime, timezone
from typing import Any

from .schema import get_db


def _today_str() -> str:
    """Return today's date as YYYY-MM-DD string (UTC)."""
    return datetime.now(timezone.utc).strftime("%Y-%m-%d")


def _yesterday_str() -> str:
    """Return yesterday's date as YYYY-MM-DD string (UTC)."""
    yesterday = int(time.time()) - 86400
    return datetime.fromtimestamp(yesterday, tz=timezone.utc).strftime("%Y-%m-%d")


# ──────────────────────────────────────────────
# CRUD
# ──────────────────────────────────────────────

def save_daily_plan(
    outreach_id: str,
    campaign_id: str,
    plan_date: str,
    planned_actions: list[dict],
    plan_source: str = "llm",
) -> str:
    """Create or replace a daily plan for a prospect. Returns plan ID."""
    plan_id = uuid.uuid4().hex[:12]
    now = int(time.time())
    db = get_db()
    db.execute(
        """INSERT OR REPLACE INTO prospect_daily_plans
           (id, outreach_id, campaign_id, plan_date, planned_actions,
            executed_actions, plan_source, created_at, updated_at)
           VALUES (?, ?, ?, ?, ?, '[]', ?, ?, ?)""",
        (
            plan_id, outreach_id, campaign_id, plan_date,
            json.dumps(planned_actions), plan_source, now, now,
        ),
    )
    db.commit()
    db.close()
    return plan_id


def get_daily_plan(outreach_id: str, plan_date: str = "") -> dict[str, Any] | None:
    """Get today's plan for an outreach. Returns None if no plan exists."""
    if not plan_date:
        plan_date = _today_str()
    db = get_db()
    row = db.execute(
        "SELECT * FROM prospect_daily_plans WHERE outreach_id = ? AND plan_date = ?",
        (outreach_id, plan_date),
    ).fetchone()
    db.close()
    if not row:
        return None
    result = dict(row)
    result["planned_actions"] = json.loads(result.get("planned_actions") or "[]")
    result["executed_actions"] = json.loads(result.get("executed_actions") or "[]")
    return result


def get_campaign_daily_plans(campaign_id: str, plan_date: str = "") -> list[dict]:
    """Get all daily plans for a campaign on a given date."""
    if not plan_date:
        plan_date = _today_str()
    db = get_db()
    rows = db.execute(
        """SELECT p.*, o.status as outreach_status
           FROM prospect_daily_plans p
           JOIN outreaches o ON p.outreach_id = o.id
           WHERE p.campaign_id = ? AND p.plan_date = ?""",
        (campaign_id, plan_date),
    ).fetchall()
    db.close()
    plans = []
    for r in rows:
        d = dict(r)
        d["planned_actions"] = json.loads(d.get("planned_actions") or "[]")
        d["executed_actions"] = json.loads(d.get("executed_actions") or "[]")
        plans.append(d)
    return plans


def mark_action_executed(
    outreach_id: str,
    plan_date: str,
    action_type: str,
    result: str = "",
    job_id: str = "",
) -> None:
    """Append an executed action to a plan's executed_actions."""
    plan = get_daily_plan(outreach_id, plan_date)
    if not plan:
        return
    executed = plan["executed_actions"]
    executed.append({
        "action_type": action_type,
        "executed_at": int(time.time()),
        "result": result[:200],
        "job_id": job_id,
    })
    db = get_db()
    db.execute(
        "UPDATE prospect_daily_plans SET executed_actions = ?, updated_at = ? WHERE id = ?",
        (json.dumps(executed), int(time.time()), plan["id"]),
    )
    db.commit()
    db.close()


# ──────────────────────────────────────────────
# Planning Queries
# ──────────────────────────────────────────────

def get_prospects_needing_plans(campaign_id: str) -> list[dict]:
    """Get active outreaches that don't have a plan for today.

    Returns outreaches in statuses: pending, invited, connected, messaged, replied
    that have no prospect_daily_plans row for today's date.
    Joins contacts for profile data and engagement counts.
    """
    today = _today_str()
    db = get_db()
    rows = db.execute(
        """SELECT o.id as outreach_id, o.campaign_id, o.status, o.followup_count,
               o.invited_at, o.accepted_at, o.first_reply_at, o.memory_json,
               c.name, c.title, c.company, c.linkedin_url, c.linkedin_id,
               c.fit_score, c.profile_json, c.analysis_json,
               (SELECT COUNT(*) FROM engagements e WHERE e.outreach_id = o.id) as engagement_count,
               (SELECT GROUP_CONCAT(e.action_type) FROM engagements e WHERE e.outreach_id = o.id) as engagement_types,
               (SELECT COUNT(*) FROM messages m WHERE m.outreach_id = o.id) as message_count,
               (SELECT MAX(m.timestamp) FROM messages m WHERE m.outreach_id = o.id) as last_message_at
           FROM outreaches o
           JOIN contacts c ON o.contact_id = c.id
           WHERE o.campaign_id = ?
             AND o.status IN ('pending', 'invited', 'connected', 'messaged', 'replied')
             AND NOT EXISTS (
                 SELECT 1 FROM prospect_daily_plans p
                 WHERE p.outreach_id = o.id AND p.plan_date = ?
             )
           ORDER BY c.fit_score DESC""",
        (campaign_id, today),
    ).fetchall()
    db.close()
    return [dict(r) for r in rows]


def has_daily_plan(outreach_id: str) -> bool:
    """Check if an outreach has a daily plan for today. Fails open (False on error)."""
    try:
        today = _today_str()
        db = get_db()
        row = db.execute(
            "SELECT 1 FROM prospect_daily_plans WHERE outreach_id = ? AND plan_date = ?",
            (outreach_id, today),
        ).fetchone()
        db.close()
        return row is not None
    except Exception:
        return False


# ──────────────────────────────────────────────
# Feedback Loop
# ──────────────────────────────────────────────

def score_yesterday_plans() -> int:
    """Score all of yesterday's plans based on outreach status changes.

    Scoring:
      replied → +3, accepted invite → +2, profile_viewed_back → +1,
      no change → 0, declined/ignored → -1
    """
    from ..constants import (
        STRATEGIST_SCORE_REPLIED,
        STRATEGIST_SCORE_ACCEPTED,
        STRATEGIST_SCORE_NO_RESPONSE,
        STRATEGIST_SCORE_DECLINED,
    )

    yesterday = _yesterday_str()
    db = get_db()
    plans = db.execute(
        """SELECT p.id, p.outreach_id, p.planned_actions, p.executed_actions,
               o.status as current_status, o.first_reply_at, o.accepted_at
           FROM prospect_daily_plans p
           JOIN outreaches o ON p.outreach_id = o.id
           WHERE p.plan_date = ? AND p.feedback_score IS NULL""",
        (yesterday,),
    ).fetchall()

    scored = 0
    now = int(time.time())
    yesterday_ts = now - 86400

    for plan in plans:
        plan = dict(plan)
        status = plan.get("current_status", "")
        reply_at = plan.get("first_reply_at") or 0
        accept_at = plan.get("accepted_at") or 0

        # Score based on what happened since yesterday
        if reply_at and reply_at >= yesterday_ts:
            score = STRATEGIST_SCORE_REPLIED
        elif accept_at and accept_at >= yesterday_ts:
            score = STRATEGIST_SCORE_ACCEPTED
        elif status in ("closed_unhappy", "opted_out", "skipped"):
            score = STRATEGIST_SCORE_DECLINED
        else:
            score = STRATEGIST_SCORE_NO_RESPONSE

        db.execute(
            "UPDATE prospect_daily_plans SET feedback_score = ?, updated_at = ? WHERE id = ?",
            (score, now, plan["id"]),
        )
        scored += 1

    db.commit()
    db.close()
    return scored


def get_feedback_data(days: int = 7, top_n: int = 10) -> dict[str, Any]:
    """Get top N best and worst plans from the last N days for LLM feedback."""
    cutoff = datetime.now(timezone.utc).strftime("%Y-%m-%d")
    start_ts = int(time.time()) - (days * 86400)
    start_date = datetime.fromtimestamp(start_ts, tz=timezone.utc).strftime("%Y-%m-%d")

    db = get_db()

    best = db.execute(
        """SELECT p.planned_actions, p.executed_actions, p.feedback_score,
               c.title, c.company, o.status
           FROM prospect_daily_plans p
           JOIN outreaches o ON p.outreach_id = o.id
           JOIN contacts c ON o.contact_id = c.id
           WHERE p.plan_date >= ? AND p.plan_date < ? AND p.feedback_score IS NOT NULL
           ORDER BY p.feedback_score DESC
           LIMIT ?""",
        (start_date, cutoff, top_n),
    ).fetchall()

    worst = db.execute(
        """SELECT p.planned_actions, p.executed_actions, p.feedback_score,
               c.title, c.company, o.status
           FROM prospect_daily_plans p
           JOIN outreaches o ON p.outreach_id = o.id
           JOIN contacts c ON o.contact_id = c.id
           WHERE p.plan_date >= ? AND p.plan_date < ? AND p.feedback_score IS NOT NULL
           ORDER BY p.feedback_score ASC
           LIMIT ?""",
        (start_date, cutoff, top_n),
    ).fetchall()

    db.close()

    def _fmt(rows: list) -> list[dict]:
        result = []
        for r in rows:
            d = dict(r)
            d["planned_actions"] = json.loads(d.get("planned_actions") or "[]")
            d["executed_actions"] = json.loads(d.get("executed_actions") or "[]")
            result.append(d)
        return result

    return {"best": _fmt(best), "worst": _fmt(worst)}
