"""Tests for platoon.data.models — Pydantic tool-input models.

Covers:
    - ToolRecord.from_csv_row() coercion (str→float, str→int, str→date, str→bool)
    - ToolRecord.validate_csv() batch validation and error collection
    - List field parsing (comma-separated, JSON array, empty)
    - Field constraints (gt, ge, etc.)
    - All 7 model types
"""

from datetime import date

import pytest

from platoon.data.models import (
    CustomerRecord,
    DemandRecord,
    DemandSlot,
    InventorySnapshot,
    OrderLine,
    ProductRecord,
    StaffMember,
    ToolRecord,
    _parse_list,
)


# ===========================================================================
# _parse_list helper
# ===========================================================================


class TestParseList:
    def test_empty_string(self):
        assert _parse_list("") == []

    def test_none(self):
        assert _parse_list(None) == []

    def test_comma_separated(self):
        assert _parse_list("math,physics,chemistry") == ["math", "physics", "chemistry"]

    def test_comma_separated_with_spaces(self):
        assert _parse_list("math, physics, chemistry") == ["math", "physics", "chemistry"]

    def test_json_array(self):
        assert _parse_list('["math","physics"]') == ["math", "physics"]

    def test_single_value(self):
        assert _parse_list("math") == ["math"]

    def test_passthrough_list(self):
        assert _parse_list(["a", "b"]) == ["a", "b"]


# ===========================================================================
# ProductRecord
# ===========================================================================


class TestProductRecord:
    def test_from_csv_row(self):
        row = {
            "product_id": "PROD-1001",
            "sku": "SKU-1001-A",
            "title": "Widget",
            "category": "Electronics",
            "price": "29.99",
            "cost": "12.50",
            "base_daily_demand": "15.3",
            "lead_time_days": "7",
            "weight_kg": "0.5",
            "status": "active",
            "intermittent": "False",
            "initial_stock": "100",
        }
        p = ProductRecord.from_csv_row(row)
        assert p.product_id == "PROD-1001"
        assert p.price == 29.99
        assert p.cost == 12.50
        assert p.base_daily_demand == 15.3
        assert p.lead_time_days == 7
        assert p.intermittent is False
        assert p.initial_stock == 100

    def test_intermittent_true(self):
        row = {
            "product_id": "P1", "sku": "S1", "price": "10", "cost": "5",
            "base_daily_demand": "1", "lead_time_days": "3", "intermittent": "True",
        }
        p = ProductRecord.from_csv_row(row)
        assert p.intermittent is True

    def test_intermittent_numeric(self):
        row = {
            "product_id": "P1", "sku": "S1", "price": "10", "cost": "5",
            "base_daily_demand": "1", "lead_time_days": "3", "intermittent": "1",
        }
        p = ProductRecord.from_csv_row(row)
        assert p.intermittent is True

    def test_price_must_be_positive(self):
        row = {
            "product_id": "P1", "sku": "S1", "price": "0", "cost": "5",
            "base_daily_demand": "1", "lead_time_days": "3",
        }
        with pytest.raises(Exception):
            ProductRecord.from_csv_row(row)

    def test_cost_must_be_positive(self):
        row = {
            "product_id": "P1", "sku": "S1", "price": "10", "cost": "-1",
            "base_daily_demand": "1", "lead_time_days": "3",
        }
        with pytest.raises(Exception):
            ProductRecord.from_csv_row(row)

    def test_defaults(self):
        row = {
            "product_id": "P1", "sku": "S1", "price": "10", "cost": "5",
            "base_daily_demand": "1", "lead_time_days": "3",
        }
        p = ProductRecord.from_csv_row(row)
        assert p.title == ""
        assert p.status == "active"
        assert p.intermittent is False
        assert p.initial_stock == 0


# ===========================================================================
# DemandRecord
# ===========================================================================


class TestDemandRecord:
    def test_from_csv_row(self):
        row = {
            "date": "2024-06-15",
            "product_id": "PROD-1001",
            "sku": "SKU-1001-A",
            "category": "Electronics",
            "units_sold": "42",
        }
        d = DemandRecord.from_csv_row(row)
        assert d.date == date(2024, 6, 15)
        assert d.product_id == "PROD-1001"
        assert d.units_sold == 42

    def test_units_sold_non_negative(self):
        row = {"date": "2024-01-01", "product_id": "P1", "units_sold": "-1"}
        with pytest.raises(Exception):
            DemandRecord.from_csv_row(row)

    def test_date_parsing(self):
        row = {"date": "2025-12-31", "product_id": "P1", "units_sold": "0"}
        d = DemandRecord.from_csv_row(row)
        assert d.date == date(2025, 12, 31)


# ===========================================================================
# OrderLine
# ===========================================================================


class TestOrderLine:
    def test_from_csv_row(self):
        row = {
            "order_id": "ORD-100001",
            "customer_id": "CUST-10001",
            "order_date": "2024-03-15",
            "product_id": "PROD-1001",
            "quantity": "2",
            "unit_price": "29.99",
            "line_total": "59.98",
            "discount": "0",
            "financial_status": "paid",
            "fulfillment_status": "fulfilled",
            "currency": "USD",
        }
        o = OrderLine.from_csv_row(row)
        assert o.order_id == "ORD-100001"
        assert o.quantity == 2
        assert o.line_total == 59.98

    def test_defaults(self):
        row = {"order_id": "O1", "product_id": "P1"}
        o = OrderLine.from_csv_row(row)
        assert o.quantity == 1
        assert o.currency == "USD"


# ===========================================================================
# InventorySnapshot
# ===========================================================================


class TestInventorySnapshot:
    def test_from_csv_row(self):
        row = {
            "date": "2024-06-15",
            "product_id": "P1",
            "opening_stock": "100",
            "units_sold": "10",
            "units_received": "0",
            "closing_stock": "90",
            "cost_per_unit": "12.50",
            "stock_value": "1125.00",
        }
        inv = InventorySnapshot.from_csv_row(row)
        assert inv.date == date(2024, 6, 15)
        assert inv.opening_stock == 100
        assert inv.closing_stock == 90


# ===========================================================================
# CustomerRecord
# ===========================================================================


class TestCustomerRecord:
    def test_from_csv_row(self):
        row = {
            "customer_id": "CUST-10001",
            "email": "test@example.com",
            "first_name": "Alice",
            "last_name": "Smith",
            "country": "US",
            "created_at": "2024-01-15",
        }
        c = CustomerRecord.from_csv_row(row)
        assert c.customer_id == "CUST-10001"
        assert c.email == "test@example.com"
        assert c.country == "US"


# ===========================================================================
# StaffMember
# ===========================================================================


class TestStaffMember:
    def test_from_csv_row_with_skills(self):
        row = {
            "staff_id": "T-1",
            "name": "Alice",
            "hourly_rate": "25",
            "max_hours_per_week": "40",
            "available_days": "Monday,Tuesday,Wednesday",
            "staff_type": "full_time",
            "skills": "math,physics,AP_calc",
        }
        s = StaffMember.from_csv_row(row)
        assert s.staff_id == "T-1"
        assert s.hourly_rate == 25.0
        assert s.available_days == ["Monday", "Tuesday", "Wednesday"]
        assert s.skills == ["math", "physics", "AP_calc"]

    def test_empty_skills(self):
        row = {
            "staff_id": "T-1", "name": "Bob",
            "hourly_rate": "20", "skills": "",
        }
        s = StaffMember.from_csv_row(row)
        assert s.skills == []

    def test_no_skills_field(self):
        row = {
            "staff_id": "T-1", "name": "Bob",
            "hourly_rate": "20",
        }
        s = StaffMember.from_csv_row(row)
        assert s.skills == []

    def test_hourly_rate_must_be_positive(self):
        row = {"staff_id": "T-1", "name": "X", "hourly_rate": "0"}
        with pytest.raises(Exception):
            StaffMember.from_csv_row(row)


# ===========================================================================
# DemandSlot
# ===========================================================================


class TestDemandSlot:
    def test_from_csv_row(self):
        row = {
            "slot_label": "Monday_math",
            "hours_needed": "4.0",
            "required_skills": "math,AP_calc",
        }
        slot = DemandSlot.from_csv_row(row)
        assert slot.slot_label == "Monday_math"
        assert slot.hours_needed == 4.0
        assert slot.required_skills == ["math", "AP_calc"]

    def test_empty_skills_means_any(self):
        row = {"slot_label": "Monday_general", "hours_needed": "8.0", "required_skills": ""}
        slot = DemandSlot.from_csv_row(row)
        assert slot.required_skills == []

    def test_hours_must_be_positive(self):
        row = {"slot_label": "X", "hours_needed": "0"}
        with pytest.raises(Exception):
            DemandSlot.from_csv_row(row)


# ===========================================================================
# validate_csv batch validation
# ===========================================================================


class TestValidateCSV:
    def test_all_valid(self):
        rows = [
            {"date": "2024-01-01", "product_id": "P1", "units_sold": "10"},
            {"date": "2024-01-02", "product_id": "P1", "units_sold": "15"},
        ]
        records = DemandRecord.validate_csv(rows)
        assert len(records) == 2
        assert records[0].units_sold == 10

    def test_partial_failure(self):
        rows = [
            {"date": "2024-01-01", "product_id": "P1", "units_sold": "10"},
            {"date": "bad-date", "product_id": "P1", "units_sold": "15"},
            {"date": "2024-01-03", "product_id": "P1", "units_sold": "20"},
        ]
        with pytest.raises(ValueError) as exc_info:
            DemandRecord.validate_csv(rows)
        exc = exc_info.value
        assert len(exc.errors) == 1
        assert exc.errors[0]["row"] == 1
        assert len(exc.valid_records) == 2

    def test_empty_input(self):
        records = DemandRecord.validate_csv([])
        assert records == []
