from datetime import date, timedelta

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from app.database import Base
from app.models import (
    AcademicPeriodWindow,
    Evaluation,
    EvaluationWorkflow,
    Section,
    Subject,
    User,
)
from app.services.workflow import (
    evaluation_config_window_open,
    grade_entry_state,
    institution_now,
    mark_conducted,
    pending_article112,
    planning_window_open,
)


def make_db():
    engine = create_engine("sqlite:///:memory:")
    Base.metadata.create_all(engine)
    return sessionmaker(bind=engine)()


def seed_basic(db):
    user = User(username="doc", full_name="Docente", role="docente", password_hash="x")
    section = Section(name="1ERO A", grade_level="1ERO", letter="A")
    subject = Subject(name="Matemática")
    db.add_all([user, section, subject])
    db.flush()
    return user, section, subject


def test_pending_article112_blocks_same_section_subject():
    db = make_db()
    user, section, subject = seed_basic(db)
    second = Evaluation(
        section_id=section.id,
        subject_id=subject.id,
        teacher_id=user.id,
        title="Artículo 112 - Prueba",
        is_article112=True,
        status="draft",
    )
    db.add(second)
    db.commit()
    blocker = pending_article112(db, section.id, subject.id)
    assert blocker is not None
    assert blocker.id == second.id


def test_published_article112_no_longer_blocks():
    db = make_db()
    user, section, subject = seed_basic(db)
    second = Evaluation(
        section_id=section.id,
        subject_id=subject.id,
        teacher_id=user.id,
        title="Artículo 112 - Prueba",
        is_article112=True,
        status="published",
    )
    db.add(second)
    db.commit()
    assert pending_article112(db, section.id, subject.id) is None


def test_mark_conducted_sets_48_hour_deadline():
    workflow = EvaluationWorkflow(evaluation_id=1)
    actual = institution_now() - timedelta(hours=1)
    mark_conducted(workflow, actual)
    assert workflow.grades_due_at == actual + timedelta(hours=48)


def test_overdue_grade_entry_is_blocked():
    db = make_db()
    user, section, subject = seed_basic(db)
    evaluation = Evaluation(
        section_id=section.id,
        subject_id=subject.id,
        teacher_id=user.id,
        title="Prueba",
        status="draft",
    )
    db.add(evaluation)
    db.flush()
    workflow = EvaluationWorkflow(
        evaluation_id=evaluation.id,
        conducted_at=institution_now() - timedelta(hours=50),
        grades_due_at=institution_now() - timedelta(hours=2),
    )
    state = grade_entry_state(evaluation, workflow)
    assert state["allowed"] is False
    assert state["overdue"] is True
    assert state["state"] == "overdue"


def test_period_windows_are_enforced():
    today = institution_now().date()
    window = AcademicPeriodWindow(
        school_year="2025-2026",
        name="I Momento",
        planning_start=today - timedelta(days=1),
        planning_end=today + timedelta(days=1),
        evaluation_config_start=today - timedelta(days=2),
        evaluation_config_end=today - timedelta(days=1),
    )
    assert planning_window_open(window, today) is True
    assert evaluation_config_window_open(window, today) is False
