"""Pydantic schemas for the jira_cli Lambda event/response contracts.""" from typing import Literal from pydantic import BaseModel, Field class Ticket(BaseModel): """A parsed Jira ticket (offboarding or suspension). ``last_working_day`` carries the ticket's effective date: the last day of employment for offboarding tickets, or the suspension start date for suspension tickets. The field name is retained across both ticket types so downstream consumers (e.g. the ``add-due-date`` action) stay uniform. """ id: str email: str full_name: str last_working_day: str class QueryOffboardingTicketsEvent(BaseModel): """Event for the 'query-offboarding-tickets' action.""" action: Literal['query-offboarding-tickets'] dry_run: bool = False class QueryOffboardingTicketsResponse(BaseModel): """Response from the 'query-offboarding-tickets' action.""" tickets: list[Ticket] class QueryApprovedTicketsEvent(BaseModel): """Event for the 'query-approved-tickets' action.""" action: Literal['query-approved-tickets'] dry_run: bool = False class QueryApprovedTicketsResponse(BaseModel): """Response from the 'query-approved-tickets' action.""" tickets: list[Ticket] class QuerySuspendTicketsEvent(BaseModel): """Event for the 'query-suspend-tickets' action.""" action: Literal['query-suspend-tickets'] dry_run: bool = False class QuerySuspendTicketsResponse(BaseModel): """Response from the 'query-suspend-tickets' action.""" tickets: list[Ticket] class QueryApprovedSuspendTicketsEvent(BaseModel): """Event for the 'query-approved-suspend-tickets' action.""" action: Literal['query-approved-suspend-tickets'] dry_run: bool = False class QueryApprovedSuspendTicketsResponse(BaseModel): """Response from the 'query-approved-suspend-tickets' action.""" tickets: list[Ticket] class ValidateTicketEvent(BaseModel): """Event for the 'validate-ticket' action.""" action: Literal['validate-ticket'] ticket_id: str dry_run: bool = False class ValidateTicketResponse(BaseModel): """Response from the 'validate-ticket' action.""" ticket_id: str valid: bool warnings: list[str] class AddCommentEvent(BaseModel): """Event for the 'add-comment' action.""" action: Literal['add-comment'] ticket_id: str comment: str dry_run: bool = False class AddCommentResponse(BaseModel): """Response from the 'add-comment' action.""" ticket_id: str dry_run: bool commented: bool class AddDueDateEvent(BaseModel): """Event for the 'add-due-date' action.""" action: Literal['add-due-date'] ticket_id: str due_date: str = Field(pattern=r'^\d{4}-\d{2}-\d{2}$') dry_run: bool = False class AddDueDateResponse(BaseModel): """Response from the 'add-due-date' action.""" ticket_id: str dry_run: bool due_date_set: bool class AddLabelEvent(BaseModel): """Event for the 'add-label' action.""" action: Literal['add-label'] ticket_id: str label: str dry_run: bool = False class AddLabelResponse(BaseModel): """Response from the 'add-label' action.""" ticket_id: str dry_run: bool label_added: bool class CloseTicketEvent(BaseModel): """Event for the 'close-ticket' action.""" action: Literal['close-ticket'] ticket_id: str target_status: str = 'Closed' dry_run: bool = False class CloseTicketResponse(BaseModel): """Response from the 'close-ticket' action.""" ticket_id: str dry_run: bool closed: bool class CompletedTicket(BaseModel): """A ticket eligible for closing — only the key is needed. Deliberately lighter than ``Ticket``: closing requires only the issue key, so this model does not depend on description parsing (email / full_name / last_working_day), which would otherwise cause closeable tickets with drifted descriptions to be soft-skipped. """ id: str class QueryCompletedTicketsEvent(BaseModel): """Event for the 'query-completed-tickets' action.""" action: Literal['query-completed-tickets'] dry_run: bool = False class QueryCompletedTicketsResponse(BaseModel): """Response from the 'query-completed-tickets' action.""" tickets: list[CompletedTicket]