# tests/test_resume_optimizer.py
"""Tests for scripts/resume_optimizer.py"""
import json
from unittest.mock import patch


# ── Fixtures ─────────────────────────────────────────────────────────────────

SAMPLE_RESUME = {
    "name": "Alex Rivera",
    "email": "alex@example.com",
    "phone": "555-1234",
    "career_summary": "Experienced Customer Success Manager with a track record of growth.",
    "skills": ["Salesforce", "Python", "customer success"],
    "experience": [
        {
            "title": "Customer Success Manager",
            "company": "Acme Corp",
            "start_date": "2021",
            "end_date": "present",
            "bullets": [
                "Managed a portfolio of 120 enterprise accounts.",
                "Reduced churn by 18% through proactive outreach.",
            ],
        },
        {
            "title": "Support Engineer",
            "company": "Beta Inc",
            "start_date": "2018",
            "end_date": "2021",
            "bullets": ["Resolved escalations for top-tier clients."],
        },
    ],
    "education": [
        {
            "degree": "B.S.",
            "field": "Computer Science",
            "institution": "State University",
            "graduation_year": "2018",
        }
    ],
    "achievements": [],
}

SAMPLE_JD = (
    "We are looking for a Customer Success Manager with Gainsight, cross-functional "
    "leadership experience, and strong stakeholder management skills. AWS knowledge a plus."
)


# ── extract_jd_signals ────────────────────────────────────────────────────────

def test_extract_jd_signals_returns_list():
    """extract_jd_signals returns a list even when LLM and TF-IDF both fail."""
    from scripts.resume_optimizer import extract_jd_signals

    with patch("scripts.llm_router.LLMRouter") as MockRouter:
        MockRouter.return_value.complete.side_effect = Exception("no LLM")
        result = extract_jd_signals(SAMPLE_JD, resume_text="Python developer")

    assert isinstance(result, list)


def test_extract_jd_signals_llm_path_parses_json_array():
    """extract_jd_signals merges LLM-extracted signals with TF-IDF gaps."""
    from scripts.resume_optimizer import extract_jd_signals

    llm_response = '["Gainsight", "cross-functional leadership", "stakeholder management"]'

    with patch("scripts.llm_router.LLMRouter") as MockRouter:
        MockRouter.return_value.complete.return_value = llm_response
        result = extract_jd_signals(SAMPLE_JD)

    assert "Gainsight" in result
    assert "cross-functional leadership" in result


def test_extract_jd_signals_deduplicates():
    """extract_jd_signals deduplicates terms across LLM and TF-IDF sources."""
    from scripts.resume_optimizer import extract_jd_signals

    llm_response = '["Python", "AWS", "Python"]'

    with patch("scripts.llm_router.LLMRouter") as MockRouter:
        MockRouter.return_value.complete.return_value = llm_response
        result = extract_jd_signals(SAMPLE_JD)

    assert result.count("Python") == 1


def test_extract_jd_signals_handles_malformed_llm_json():
    """extract_jd_signals falls back gracefully when LLM returns non-JSON."""
    from scripts.resume_optimizer import extract_jd_signals

    with patch("scripts.llm_router.LLMRouter") as MockRouter:
        MockRouter.return_value.complete.return_value = "Here are some keywords: Gainsight, AWS"
        result = extract_jd_signals(SAMPLE_JD)

    # Should still return a list (may be empty if TF-IDF also silent)
    assert isinstance(result, list)


# ── prioritize_gaps ───────────────────────────────────────────────────────────

def test_prioritize_gaps_skips_existing_terms():
    """prioritize_gaps excludes terms already present in the resume."""
    from scripts.resume_optimizer import prioritize_gaps

    # "Salesforce" is already in SAMPLE_RESUME skills
    result = prioritize_gaps(["Salesforce", "Gainsight"], SAMPLE_RESUME)
    terms = [r["term"] for r in result]

    assert "Salesforce" not in terms
    assert "Gainsight" in terms


def test_prioritize_gaps_routes_tech_terms_to_skills():
    """prioritize_gaps maps known tech keywords to the skills section at priority 1."""
    from scripts.resume_optimizer import prioritize_gaps

    result = prioritize_gaps(["AWS", "Docker"], SAMPLE_RESUME)
    by_term = {r["term"]: r for r in result}

    assert by_term["AWS"]["section"] == "skills"
    assert by_term["AWS"]["priority"] == 1
    assert by_term["Docker"]["section"] == "skills"


def test_prioritize_gaps_routes_leadership_terms_to_summary():
    """prioritize_gaps maps leadership/executive signals to the summary section."""
    from scripts.resume_optimizer import prioritize_gaps

    result = prioritize_gaps(["cross-functional", "stakeholder"], SAMPLE_RESUME)
    by_term = {r["term"]: r for r in result}

    assert by_term["cross-functional"]["section"] == "summary"
    assert by_term["stakeholder"]["section"] == "summary"


def test_prioritize_gaps_multi_word_routes_to_experience():
    """Multi-word phrases not in skills/summary lists go to experience at priority 2."""
    from scripts.resume_optimizer import prioritize_gaps

    result = prioritize_gaps(["proactive client engagement"], SAMPLE_RESUME)
    assert result[0]["section"] == "experience"
    assert result[0]["priority"] == 2


def test_prioritize_gaps_single_word_is_lowest_priority():
    """Single generic words not in any list go to experience at priority 3."""
    from scripts.resume_optimizer import prioritize_gaps

    result = prioritize_gaps(["innovation"], SAMPLE_RESUME)
    assert result[0]["priority"] == 3


def test_prioritize_gaps_sorted_by_priority():
    """prioritize_gaps output is sorted ascending by priority (1 first)."""
    from scripts.resume_optimizer import prioritize_gaps

    gaps = ["innovation", "AWS", "cross-functional", "managed service contracts"]
    result = prioritize_gaps(gaps, SAMPLE_RESUME)
    priorities = [r["priority"] for r in result]

    assert priorities == sorted(priorities)


# ── hallucination_check ───────────────────────────────────────────────────────

def test_hallucination_check_passes_unchanged_resume():
    """hallucination_check returns True when rewrite has no new employers or institutions."""
    from scripts.resume_optimizer import hallucination_check

    # Shallow rewrite: same structure
    rewritten = {
        **SAMPLE_RESUME,
        "career_summary": "Dynamic CSM with cross-functional stakeholder management experience.",
    }
    assert hallucination_check(SAMPLE_RESUME, rewritten) is True


def test_hallucination_check_fails_on_new_employer():
    """hallucination_check returns False when a new company is introduced."""
    from scripts.resume_optimizer import hallucination_check

    fabricated_entry = {
        "title": "VP of Customer Success",
        "company": "Fabricated Corp",
        "start_date": "2019",
        "end_date": "2021",
        "bullets": ["Led a team of 30."],
    }
    rewritten = dict(SAMPLE_RESUME)
    rewritten["experience"] = SAMPLE_RESUME["experience"] + [fabricated_entry]

    assert hallucination_check(SAMPLE_RESUME, rewritten) is False


def test_hallucination_check_fails_on_new_institution():
    """hallucination_check returns False when a new educational institution appears."""
    from scripts.resume_optimizer import hallucination_check

    rewritten = dict(SAMPLE_RESUME)
    rewritten["education"] = [
        *SAMPLE_RESUME["education"],
        {"degree": "M.S.", "field": "Data Science", "institution": "MIT", "graduation_year": "2020"},
    ]

    assert hallucination_check(SAMPLE_RESUME, rewritten) is False


# ── render_resume_text ────────────────────────────────────────────────────────

def test_render_resume_text_contains_all_sections():
    """render_resume_text produces plain text containing all resume sections."""
    from scripts.resume_optimizer import render_resume_text

    text = render_resume_text(SAMPLE_RESUME)

    assert "Alex Rivera" in text
    assert "SUMMARY" in text
    assert "EXPERIENCE" in text
    assert "Customer Success Manager" in text
    assert "Acme Corp" in text
    assert "EDUCATION" in text
    assert "State University" in text
    assert "SKILLS" in text
    assert "Salesforce" in text


def test_render_resume_text_omits_empty_sections():
    """render_resume_text skips sections that have no content."""
    from scripts.resume_optimizer import render_resume_text

    sparse = {
        "name": "Jordan Lee",
        "email": "",
        "phone": "",
        "career_summary": "",
        "skills": [],
        "experience": [],
        "education": [],
        "achievements": [],
    }
    text = render_resume_text(sparse)

    assert "EXPERIENCE" not in text
    assert "SKILLS" not in text


# ── db integration ────────────────────────────────────────────────────────────

def test_save_and_get_optimized_resume(tmp_path):
    """save_optimized_resume persists and get_optimized_resume retrieves the data."""
    from scripts.db import init_db, save_optimized_resume, get_optimized_resume

    db_path = tmp_path / "test.db"
    init_db(db_path)

    # Insert a minimal job to satisfy FK
    import sqlite3
    conn = sqlite3.connect(db_path)
    conn.execute(
        "INSERT INTO jobs (id, title, company, url, source, status) VALUES (1, 'CSM', 'Acme', 'http://x.com', 'test', 'approved')"
    )
    conn.commit()
    conn.close()

    gap_report = json.dumps([{"term": "Gainsight", "section": "skills", "priority": 1, "rationale": "test"}])
    save_optimized_resume(db_path, job_id=1, text="Rewritten resume text.", gap_report=gap_report)

    result = get_optimized_resume(db_path, job_id=1)
    assert result["optimized_resume"] == "Rewritten resume text."
    parsed = json.loads(result["ats_gap_report"])
    assert parsed[0]["term"] == "Gainsight"


def test_get_optimized_resume_returns_empty_for_missing(tmp_path):
    """get_optimized_resume returns empty strings when no record exists."""
    from scripts.db import init_db, get_optimized_resume

    db_path = tmp_path / "test.db"
    init_db(db_path)

    result = get_optimized_resume(db_path, job_id=999)
    assert result["optimized_resume"] == ""
    assert result["ats_gap_report"] == ""
