"""
FedComp Index - Federal contractor posture scoring.

Scores federal contractors on a 0-100 scale based on public award data
from USASpending.gov. Each contractor is assigned a FedComp Index score
and a posture class (Class 1, Class 2, or Class 3).

Methodology: https://fedcompindex.org/methodology/
Data: https://huggingface.co/datasets/npetro6/nevada-federal-contractors
"""

__version__ = "2026.3.2"

import math
from datetime import date, datetime
from enum import Enum


class PostureClass(Enum):
    """Federal contractor posture classification based on FedComp Index score."""
    CLASS_1 = "Class 1"  # Score 60+, ~$100M+ in awards
    CLASS_2 = "Class 2"  # Score 40-59, ~$5M-$100M
    CLASS_3 = "Class 3"  # Score below 40


class FedCompResult:
    """Result of a FedComp Index scoring calculation."""

    def __init__(self, fedcomp_index, posture_class, volume_driver, recency_driver):
        self.fedcomp_index = fedcomp_index
        self.posture_class = posture_class
        self.volume_driver = volume_driver
        self.recency_driver = recency_driver

    def __repr__(self):
        return (
            f"FedCompResult(fedcomp_index={self.fedcomp_index}, "
            f"posture_class={self.posture_class.value})"
        )


# Scoring constants
_W_VOLUME = 0.90
_W_RECENCY = 0.10
_LOG_MIN = 4   # log10($10K)
_LOG_MAX = 10  # log10($10B)


def _volume_driver(total_awards_usd):
    """
    Log10-scaled total award dollars, mapped to 0-100.

    $10K=0, $1M=33, $10M=50, $100M=67, $1B=83, $10B=100.
    """
    if total_awards_usd <= 0:
        return 0
    log_val = math.log10(total_awards_usd)
    return max(0, min(100, round((log_val - _LOG_MIN) / (_LOG_MAX - _LOG_MIN) * 100)))


def _recency_driver(last_award_date):
    """
    Bucketed recency of most recent award.

    Past 12 months: 100, 1-2yr: 60, 2-3yr: 30, 3-5yr: 10, older: 0.
    """
    if not last_award_date:
        return 0
    if isinstance(last_award_date, str):
        last_award_date = datetime.strptime(last_award_date[:10], "%Y-%m-%d").date()
    days_ago = (date.today() - last_award_date).days
    if days_ago <= 365:
        return 100
    elif days_ago <= 730:
        return 60
    elif days_ago <= 1095:
        return 30
    elif days_ago <= 1825:
        return 10
    return 0


def _classify(score):
    if score >= 60:
        return PostureClass.CLASS_1
    elif score >= 40:
        return PostureClass.CLASS_2
    return PostureClass.CLASS_3


def score_contractor(total_awards_usd, last_award_date=None):
    """
    Compute the FedComp Index score and posture class for a contractor.

    Args:
        total_awards_usd: Total federal award dollars over trailing 5-year window.
        last_award_date: Date of most recent award. String "YYYY-MM-DD" or
            "YYYY-MM" or a date object. Optional.

    Returns:
        FedCompResult with fedcomp_index (0-100) and posture_class.

    Example::

        from fedcomp_index import score_contractor

        result = score_contractor(
            total_awards_usd=45_000_000,
            last_award_date="2025-09-15"
        )
        print(result.fedcomp_index)   # 58
        print(result.posture_class)   # PostureClass.CLASS_2
    """
    if isinstance(last_award_date, str):
        if len(last_award_date) == 7:
            last_award_date = last_award_date + "-01"

    d1 = _volume_driver(total_awards_usd)
    d2 = _recency_driver(last_award_date)

    raw = d1 * _W_VOLUME + d2 * _W_RECENCY
    fedcomp_index = min(100, max(0, round(raw)))

    return FedCompResult(
        fedcomp_index=fedcomp_index,
        posture_class=_classify(fedcomp_index),
        volume_driver=d1,
        recency_driver=d2,
    )
