"""
JTBD × Competitor Keywords Analysis
----------------------------------
- Problem-first text
- 3 strategic scores:
    - Problem Intensity Score (PIS)
    - Solution Awareness Score (SAS)
    - Competitor Problem Coverage Score (CPCS)

Requirements:
    pip install pandas numpy scikit-learn
"""

import numpy as np
import pandas as pd
from io import StringIO
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity


# =========================================================
# 1. LEXICOANE (ajusteaza dupa domeniu)
# =========================================================

PROBLEM_TERMS = {
    "hard", "difficult", "confusing", "fails", "breaks",
    "unreliable", "inconsistent", "slow", "manual",
    "debug", "maintain", "scale", "complex", "unmanageable"
}

FAILURE_VERBS = {
    "fails", "breaks", "crashes", "hallucinates",
    "timeouts", "loops", "freezes"
}

SOLUTION_TERMS = {
    "framework", "platform", "tool", "library",
    "api", "sdk", "llm", "agent", "rag",
    "langchain", "openai", "orchestration", "workflow"
}


# =========================================================
# 2. LOADERS
# =========================================================

def load_google_keywords(path: str) -> pd.DataFrame:
    raw = pd.read_csv(path, encoding="utf-16")
    text = "\n".join(raw.iloc[1:, 0].astype(str))
    df = pd.read_csv(StringIO(text), sep="\t")

    df = df.rename(columns={
        "Keyword": "keyword",
        "Avg. monthly searches": "avg_monthly_searches",
        "Competition": "competition",
        "Top of page bid (low range)": "bid_low",
        "Top of page bid (high range)": "bid_high",
    })

    df["keyword"] = df["keyword"].astype(str)
    df["avg_monthly_searches"] = pd.to_numeric(
        df.get("avg_monthly_searches", 0), errors="coerce"
    ).fillna(0)

    return df


def load_jtbd(path: str) -> pd.DataFrame:
    df = pd.read_csv(path)
    df["jtbd_id"] = df.index
    return df


# =========================================================
# 3. TEXT BUILDERS
# =========================================================

def build_jtbd_problem_text(row):
    parts = []

    if isinstance(row.get("struggle"), str):
        parts.append(row["struggle"])

    if isinstance(row.get("situation"), str):
        parts.append(row["situation"])

    if not parts and isinstance(row.get("job_statement"), str):
        parts.append(row["job_statement"])

    return " ".join(parts).lower()


# =========================================================
# 4. SCORURI JTBD
# =========================================================

def problem_intensity_score(row):
    text = row.get("jtbd_problem_text", "")

    return (
        sum(t in text for t in PROBLEM_TERMS) * 2
        + sum(v in text for v in FAILURE_VERBS) * 3
        + len(text.split()) * 0.05
        - sum(t in text for t in SOLUTION_TERMS) * 2
    )


def solution_awareness_score(row):
    text = " ".join(
        str(row[col]).lower()
        for col in ["outcome", "job_statement", "journey_text"]
        if isinstance(row.get(col), str)
    )

    return sum(t in text for t in SOLUTION_TERMS)


# =========================================================
# 5. TF-IDF + SIMILARITATI (PROBLEM-FIRST)
# =========================================================

def compute_problem_similarity(jtbd_df, kw_df):
    jtbd_texts = jtbd_df["jtbd_problem_text"].fillna("").tolist()
    kw_texts = kw_df["keyword"].str.lower().tolist()

    corpus = jtbd_texts + kw_texts

    vectorizer = TfidfVectorizer(
        ngram_range=(1, 2),
        max_df=0.9,
        min_df=1
    )

    X = vectorizer.fit_transform(corpus)

    X_jtbd = X[:len(jtbd_texts)]
    X_kw = X[len(jtbd_texts):]

    sim_matrix = cosine_similarity(X_jtbd, X_kw)

    return sim_matrix


def competitor_problem_coverage(sim_row):
    return float(sim_row.mean())


# =========================================================
# 6. MATCHING JTBD → KEYWORDS
# =========================================================

def get_keyword_matches(
    jtbd_df,
    kw_df,
    sim_matrix,
    top_n=10,
    min_sim=0.1
):
    rows = []

    for i in range(len(jtbd_df)):
        sims = sim_matrix[i]
        top_idx = np.argsort(sims)[::-1][:top_n]

        for j in top_idx:
            if sims[j] < min_sim:
                continue

            rows.append({
                "jtbd_id": jtbd_df.iloc[i]["jtbd_id"],
                "job_cluster": jtbd_df.iloc[i].get("job_cluster"),
                "jtbd_problem_text": jtbd_df.iloc[i]["jtbd_problem_text"],
                "keyword": kw_df.iloc[j]["keyword"],
                "similarity": sims[j],
                "avg_monthly_searches": kw_df.iloc[j]["avg_monthly_searches"],
                "problem_intensity_score": jtbd_df.iloc[i]["problem_intensity_score"],
                "solution_awareness_score": jtbd_df.iloc[i]["solution_awareness_score"],
                "competitor_problem_coverage": jtbd_df.iloc[i]["competitor_problem_coverage"],
            })

    return pd.DataFrame(rows)


# =========================================================
# 7. AGREGARE PE CLUSTER
# =========================================================

def cluster_summary(jtbd_df, matches_df):
    agg = jtbd_df.groupby("job_cluster").agg(
        num_jtbd=("jtbd_id", "count"),
        avg_problem_intensity=("problem_intensity_score", "mean"),
        avg_solution_awareness=("solution_awareness_score", "mean"),
        avg_competitor_problem_coverage=("competitor_problem_coverage", "mean"),
    )

    if not matches_df.empty:
        vol = matches_df.groupby("job_cluster")["avg_monthly_searches"].sum()
        agg = agg.join(vol, how="left").fillna(0)

    return agg.reset_index()


# =========================================================
# 8. MAIN
# =========================================================

def main():
    KW_PATH = "Keyword Stats 2025-12-10 at 19_41_15.csv"
    JTBD_PATH = "all_code_agent_posts_comments_jtbd_comments__jtbd_with_job_clusters.csv"

    print("Loading data...")
    kw_df = load_google_keywords(KW_PATH)
    jtbd_df = load_jtbd(JTBD_PATH)

    print("Building problem-first JTBD text...")
    jtbd_df["jtbd_problem_text"] = jtbd_df.apply(build_jtbd_problem_text, axis=1)

    print("Computing JTBD scores...")
    jtbd_df["problem_intensity_score"] = jtbd_df.apply(problem_intensity_score, axis=1)
    jtbd_df["solution_awareness_score"] = jtbd_df.apply(solution_awareness_score, axis=1)

    print("Computing problem similarity...")
    sim_matrix = compute_problem_similarity(jtbd_df, kw_df)

    jtbd_df["competitor_problem_coverage"] = [
        competitor_problem_coverage(sim_matrix[i])
        for i in range(len(jtbd_df))
    ]

    print("Matching JTBD to keywords...")
    matches_df = get_keyword_matches(jtbd_df, kw_df, sim_matrix)

    print("Saving outputs...")
    matches_df.to_csv("jtbd_keyword_matches.csv", index=False)

    cluster_df = cluster_summary(jtbd_df, matches_df)
    cluster_df.to_csv("jtbd_cluster_opportunities.csv", index=False)

    print("DONE ✅")


if __name__ == "__main__":
    main()
