def _norm(s):
    return (s or "").lower().strip()


def _keyword_hits_name(skill_name, kw_list):
    """Совпадение имени навыка с ключами (точное, вхождение с любой стороны)."""
    sn = _norm(skill_name)
    if not sn:
        return False
    for kw in kw_list:
        k = _norm(kw)
        if not k:
            continue
        if k == sn or k in sn or sn in k:
            return True
    return False


def match_with_portfolio(student_profile, keywords):
    """Сопоставление ключевых слов с портфолио."""
    matched_skills = []
    matched_projects = []

    kw_skills = keywords.get("skills") or []
    kw_tech = keywords.get("technologies") or []
    kw_all = []
    for x in kw_skills + kw_tech:
        n = _norm(x)
        if n and n not in kw_all:
            kw_all.append(n)

    for skill in student_profile.skills.all():
        if _keyword_hits_name(skill.name, kw_all):
            matched_skills.append(skill)

    for project in student_profile.projects.all():
        project_text = (
            f"{project.title} {project.description} {project.technologies or ''}"
        ).lower()
        score = sum(1 for kw in kw_all if kw and kw in project_text)
        if score > 0:
            matched_projects.append({"project": project, "score": score})

    matched_projects.sort(key=lambda x: x["score"], reverse=True)

    return {
        "skills": matched_skills,
        "projects": [p["project"] for p in matched_projects],
        "has_match": len(matched_skills) > 0 or len(matched_projects) > 0,
    }


def match_portfolio(student_profile, keywords):
    """Алиас (в т.ч. для resume.services.matcher)."""
    return match_with_portfolio(student_profile, keywords)
