"""Manual entry creation (T-ENT-36/37): exact validation messages,
identity stamped FROM the worker, billable always true, end = start +
duration incl. midnight rollover, and the per-(tenant,user) "Manual
entries" auto-batch — created once, reused thereafter."""

from datetime import datetime
from decimal import Decimal

import pytest
from sqlalchemy import func, select

from app.models import ImportBatch
from app.services.entries_write import MANUAL_BATCH_NAME, create_entry
from app.services.errors import ServiceError


def base_payload(g) -> dict:
    return {
        "date": "2026-07-01",
        "start_time": "9:30",
        "duration": "1:30:00",
        "description": "manual work",
        "worker_party_id": str(g.parties.adi.id),
        "project_id": str(g.projects.site.id),
    }


def err(fn, *args) -> ServiceError:
    with pytest.raises(ServiceError) as exc_info:
        fn(*args)
    return exc_info.value


# ------------------------------------------------------------ validation


@pytest.mark.parametrize(
    ("field", "value", "message"),
    [
        ("date", "07/01/2026", "Date must be YYYY-MM-DD."),
        ("date", "", "Date must be YYYY-MM-DD."),
        ("duration", "", "Duration is required (HH:MM:SS or decimal hours)."),
        ("duration", "bogus", "Duration is required (HH:MM:SS or decimal hours)."),
        ("description", "  ", "Description is required."),
        ("worker_party_id", None, "Pick a team member — entries must be billable to someone."),
        ("start_time", "25:00", "Start time must be HH:MM[:SS]."),
    ],
)
def test_t_ent_36_validation_messages(g, rian, field, value, message):
    payload = base_payload(g)
    payload[field] = value
    error = err(create_entry, g.session, rian, payload)
    assert error.summary == message


def test_worker_must_exist(g, rian):
    payload = base_payload(g)
    payload["worker_party_id"] = str(g.parties.brentwood.id)  # org, not a worker
    error = err(create_entry, g.session, rian, payload)
    assert error.summary == "Selected team member not found (or not visible to you)."


def test_worker_role_cannot_create(g, gary):
    error = err(create_entry, g.session, gary, base_payload(g))
    assert error.status == 403
    assert error.summary == "You do not have permission to add entries."


# ------------------------------------------------------------ derivations


def test_t_ent_37_identity_from_worker_billable_true(g, rian):
    entry = create_entry(g.session, rian, base_payload(g))
    assert entry.source == "manual"
    assert entry.source_user_email == "info@adipramono.com"
    assert entry.source_user_name == "Adi Pramono"
    assert entry.billable is True
    assert entry.start_at == datetime(2026, 7, 1, 9, 30, 0)
    assert entry.end_at == datetime(2026, 7, 1, 11, 0, 0)
    assert entry.duration_seconds == 5400
    # money from adi's current terms + Site Rebuild worker override 20/h
    assert Decimal(str(entry.cost_amount)) == Decimal("21.00")
    assert Decimal(str(entry.billout_amount)) == Decimal("30.00")


def test_start_defaults_to_midnight_and_rollover(g, rian):
    payload = base_payload(g)
    payload["start_time"] = None
    payload["date"] = "2026-07-01"
    payload["duration"] = "25:00:00"  # rolls past midnight (B59)
    entry = create_entry(g.session, rian, payload)
    assert entry.start_at == datetime(2026, 7, 1, 0, 0, 0)
    assert entry.end_at == datetime(2026, 7, 2, 1, 0, 0)


def test_entity_chain_optional_blank_is_blocked_row(g, rian):
    payload = base_payload(g)
    payload.pop("project_id")
    entry = create_entry(g.session, rian, payload)
    assert entry.project_id is None


def test_manual_batch_created_once_per_user(g, rian, adi):
    e1 = create_entry(g.session, rian, base_payload(g))
    e2 = create_entry(g.session, rian, base_payload(g))
    assert e1.import_id == e2.import_id
    batch = g.session.get(ImportBatch, e1.import_id)
    assert batch.name == MANUAL_BATCH_NAME
    assert batch.source == "manual"
    assert batch.imported_by == g.users["rian"].id

    e3 = create_entry(g.session, adi, base_payload(g))
    assert e3.import_id != e1.import_id  # per-(tenant,user)
    manual_count = g.session.scalar(
        select(func.count()).select_from(ImportBatch).where(ImportBatch.source == "manual")
    )
    assert manual_count == 2


def test_manual_entry_visible_to_its_manager_creator(g, adi):
    """The batch link is REQUIRED — manual rows without it would be
    invisible to their creator under the scope rule (T-ENT-37 note)."""
    from app.services.reporting.entries import list_entries
    from app.services.reporting.filters import EntryFilters

    entry = create_entry(g.session, adi, base_payload(g))
    page = list_entries(g.session, adi, EntryFilters())
    assert str(entry.id) in {row["id"] for row in page.rows}
