from pydantic import BaseModel, Field, EmailStr, validator, field_validator, ConfigDict, AliasChoices
from typing import Union, List, Dict, Optional, Any
from datetime import datetime, date
from decimal import Decimal
from fastapi import Form
import json

from app.backend.schemas.helpers import _empty_str_to_none  # noqa: F401

class UserLogin(BaseModel):
    rol_id: Union[int, None]
    rut: Union[int, None]
    branch_office_id: Union[int, None]
    customer_id: Union[int, None]
    school_id: Union[int, None]
    period_year: Union[int, None] = None  # users_rols / JWT
    full_name: Union[str, None]
    email: Union[str, None]
    phone: Union[str, None]
    hashed_password: Union[str, None]

class ForgotPassword(BaseModel):
    email: str

class UpdatePassWord(BaseModel):
    email: str
    token: str
    new_password: str

# User schemas

class User(BaseModel):
    rol_id: int
    branch_office_id: Optional[int] = None
    customer_id: Optional[int] = None
    rut: Optional[str] = None
    full_name: Optional[str] = None
    fullname: Optional[str] = None  # Alias para full_name (se mapeará en el router)
    email: str
    password: str
    phone: Optional[str] = None

class UpdateUser(BaseModel):
    rol_id: int = None
    customer_id: int = None
    rut: str = None
    full_name: str = None
    email: str = None
    phone: str = None
    password: str = None
    current_password: str = None

class UserList(BaseModel):
    page: int
    rut: Optional[str] = None

class RecoverUser(BaseModel):
    email: str

class ConfirmEmail(BaseModel):
    email: str
    token: str

# Role schemas

class RolList(BaseModel):
    page: Optional[int] = None
    rol: Optional[str] = None
    per_page: int = 10

class Rol(BaseModel):
    customer_id: Optional[int] = None
    rol: str
    permissions: Optional[List[int]] = None

class UpdateRol(BaseModel):
    customer_id: int = None
    rol: str = None
    permissions: Optional[List[int]] = None

class StoreCustomerSchoolRole(BaseModel):
    """Alta de rol vinculado a un colegio del cliente (superadmin / gestión usuarios)."""
    rol: str
    permissions: Optional[List[int]] = None

class AddRolToSchoolFromExisting(BaseModel):
    """Clonar un rol del cliente a un colegio (nueva fila en `rols`)."""
    rol_id: int

# Permission schemas

class PermissionList(BaseModel):
    page: Optional[int] = None
    permission: Optional[str] = None
    per_page: int = 10

class Permission(BaseModel):
    permission: str
    permission_type_id: int
    permission_order_id: Optional[int] = None

class UpdatePermission(BaseModel):
    permission: str = None
    permission_type_id: Optional[int] = None
    permission_order_id: Optional[int] = None

# Settings schemas

class UpdateSettings(BaseModel):
    tax_value: int = None
    identification_number: str = None
    account_type: str = None
    account_number: str = None
    account_name: str = None
    account_email: str = None
    bank: str = None
    delivery_cost: int = None
    shop_address: str = None
    payment_card_url: str = None
    prepaid_discount: Optional[int] = None
    phone: str = None
    company_email: Optional[str] = None
    company_phone: Optional[str] = None
    company_whatsapp: Optional[str] = None

# Teaching schemas

class TeachingList(BaseModel):
    page: Optional[int] = None
    teaching_name: Optional[str] = None
    per_page: int = 10

class StoreTeaching(BaseModel):
    teaching_type_id: int
    teaching_name: str

class UpdateTeaching(BaseModel):
    teaching_type_id: int = None
    teaching_name: str = None

# Course schemas

class CourseList(BaseModel):
    page: Optional[int] = None
    course_name: Optional[str] = None
    teaching_id: Optional[int] = None
    per_page: int = 10
    period_year: Optional[int] = Field(
        None, ge=2000, le=2100, description="Año del período escolar (filtro listado)"
    )

class StoreCourse(BaseModel):
    teaching_id: int
    course_name: str
    period_year: Optional[int] = Field(None, ge=2000, le=2100)

class UpdateCourse(BaseModel):
    teaching_id: int = None
    course_name: str = None
    period_year: Optional[int] = Field(None, ge=2000, le=2100)

# Commune schemas

class CommuneList(BaseModel):
    commune_name: Optional[str] = None
    region_id: Optional[int] = None
    page: Optional[int] = None
    per_page: int = 10

class StoreCommune(BaseModel):
    region_id: int
    commune: str
    id: Optional[int] = None

class UpdateCommune(BaseModel):
    region_id: int = None
    commune: str = None

# Region schemas

class RegionList(BaseModel):
    region_name: Optional[str] = None
    page: Optional[int] = None
    per_page: int = 10

class StoreRegion(BaseModel):
    region: str
    id: Optional[int] = None

class UpdateRegion(BaseModel):
    region: str = None


# Province schemas (catálogo Inspection listado/provincias en BD local `provinces`)

class ProvinceList(BaseModel):
    province_name: Optional[str] = None
    region_id: Optional[int] = None
    page: Optional[int] = None
    per_page: int = 10

class StoreProvince(BaseModel):
    province: str
    region_id: int
    id: Optional[int] = None

class UpdateProvince(BaseModel):
    province: str = None
    region_id: int = None

# Native Language Proficiency schemas

class NativeLanguageProficiencyList(BaseModel):
    native_language_proficiency: Optional[str] = None

class StoreNativeLanguageProficiency(BaseModel):
    native_language_proficiency: str

class UpdateNativeLanguageProficiency(BaseModel):
    native_language_proficiency: str = None

# Documents schemas

class CreateDocumentRequest(BaseModel):
    student_name: str
    document_type_id: int
    career_type_id: Optional[int] = None

    @classmethod
    def as_form(
        cls,
        student_name: str = Form(...),
        document_type_id: int = Form(...),
        career_type_id: Optional[int] = Form(None)
    ):
        return cls(
            student_name=student_name,
            document_type_id=document_type_id,
            career_type_id=career_type_id
        )

class DocumentListRequest(BaseModel):
    document_type_id: Optional[int] = None
    career_type_id: Optional[int] = None

class UploadDocumentRequest(BaseModel):
    student_id: int

    @classmethod
    def as_form(
        cls,
        student_id: int = Form(...)
    ):
        return cls(student_id=student_id)

# Family Member schemas

class FamilyMemberList(BaseModel):
    page: Optional[int] = None
    family_member: Optional[str] = None
    per_page: int = 10

class StoreFamilyMember(BaseModel):
    family_member: str

class UpdateFamilyMember(BaseModel):
    family_member: str = None

# Student Guardian schemas

class StudentGuardianList(BaseModel):
    page: Optional[int] = None
    student_id: Optional[int] = None
    names: Optional[str] = None
    per_page: int = 10

class StoreStudentGuardian(BaseModel):
    student_id: int
    family_member_id: Optional[int] = None
    gender_id: Optional[int] = None
    identification_number: Optional[str] = None
    names: Optional[str] = None
    father_lastname: Optional[str] = None
    mother_lastname: Optional[str] = None
    born_date: Optional[str] = None
    email: Optional[str] = None
    celphone: Optional[str] = None
    city: Optional[str] = None

class UpdateStudentGuardian(BaseModel):
    student_id: Optional[int] = None
    family_member_id: Optional[int] = None
    gender_id: Optional[int] = None
    identification_number: Optional[str] = None
    names: Optional[str] = None
    father_lastname: Optional[str] = None
    mother_lastname: Optional[str] = None
    born_date: Optional[str] = None
    email: Optional[str] = None
    celphone: Optional[str] = None
    city: Optional[str] = None

# News schemas

class NewsList(BaseModel):
    page: Optional[int] = None
    title: Optional[str] = None
    per_page: int = 10

class StoreNews(BaseModel):
    title: str
    short_description: str
    description: str
    image: Optional[str] = None

    @classmethod
    def as_form(
        cls,
        title: str = Form(...),
        short_description: str = Form(...),
        description: str = Form(...)
    ):
        return cls(
            title=title,
            short_description=short_description,
            description=description
        )

class UpdateNews(BaseModel):
    title: Optional[str] = None
    short_description: Optional[str] = None
    description: Optional[str] = None

    @classmethod
    def as_form(
        cls,
        title: Optional[str] = Form(None),
        short_description: Optional[str] = Form(None),
        description: Optional[str] = Form(None)
    ):
        return cls(
            title=title if title else None,
            short_description=short_description if short_description else None,
            description=description if description else None
        )

# Nationality schemas

class NationalityList(BaseModel):
    page: Optional[int] = None
    nationality: Optional[str] = None
    per_page: int = 10

class StoreNationality(BaseModel):
    nationality: str

class UpdateNationality(BaseModel):
    nationality: str = None

# Gender schemas

class GenderList(BaseModel):
    page: Optional[int] = None
    gender: Optional[str] = None
    per_page: int = 10

class StoreGender(BaseModel):
    gender: str

class UpdateGender(BaseModel):
    gender: str = None

# School schemas

class SchoolList(BaseModel):
    page: Optional[int] = None
    school_name: Optional[str] = None
    customer_id: Optional[int] = None
    per_page: int = 10

class StoreSchool(BaseModel):
    school_name: str
    school_address: str
    director_name: str
    community_school_password: str

class UpdateSchool(BaseModel):
    school_name: Optional[str] = None
    school_address: Optional[str] = None
    director_name: Optional[str] = None
    community_school_password: Optional[str] = None

# Student schemas

class StudentList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    rut: Optional[str] = None
    names: Optional[str] = None
    identification_number: Optional[str] = None
    course_id: Optional[int] = None
    period_year: Optional[int] = None  # Filtrar estudiantes por año (ej. 2026)

class StudentAcademicInfo(BaseModel):
    special_educational_need_id: Optional[int] = None
    course_id: Optional[int] = None
    platform_status_id: Optional[int] = None
    resolution_number: Optional[str] = None
    sip_admission_year: Optional[int] = None
    diagnostic_date: Optional[date] = None
    psychopedagogical_evaluation_status: Optional[str] = None
    psychopedagogical_evaluation_year: Optional[int] = None

class StudentPersonalInfo(BaseModel):
    region_id: Optional[int] = None
    commune_id: Optional[int] = None
    gender_id: Optional[int] = None
    proficiency_native_language_id: Optional[int] = None
    proficiency_language_used_id: Optional[int] = None
    identification_number: Optional[str] = None
    names: Optional[str] = None
    father_lastname: Optional[str] = None
    mother_lastname: Optional[str] = None
    social_name: Optional[str] = None
    born_date: Optional[str] = None
    nationality_id: Optional[int] = None
    address: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None
    native_language: Optional[str] = None
    language_usually_used: Optional[str] = None

class StoreStudent(BaseModel):
    identification_number: str
    names: str
    father_lastname: str
    mother_lastname: str
    course_id: Optional[int] = None
    period_year: Optional[int] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    born_date: Optional[str] = None
    # Si True (por defecto), antes de crear se consulta la API Inspection y se completan datos disponibles
    sync_inspection: bool = True

class UpdateStudent(BaseModel):
    # Campos que vienen del frontend ya mapeados a nombres de BD
    identification_number: Optional[str] = None
    period_year: Optional[int] = None
    names: Optional[str] = None
    father_lastname: Optional[str] = None
    mother_lastname: Optional[str] = None
    social_name: Optional[str] = None
    gender_id: Optional[int] = None
    born_date: Optional[str] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    address: Optional[str] = None
    region_id: Optional[int] = None
    commune_id: Optional[int] = None
    nationality_id: Optional[int] = None
    native_language: Optional[str] = None
    proficiency_native_language_id: Optional[int] = None
    language_usually_used: Optional[str] = None
    proficiency_language_used_id: Optional[int] = None
    # Campos académicos
    special_educational_need_id: Optional[int] = None
    course_id: Optional[int] = None
    platform_status_id: Optional[int] = None
    resolution_number: Optional[str] = None
    sip_admission_year: Optional[int] = None
    diagnostic_date: Optional[date] = None
    psychopedagogical_evaluation_status: Optional[str] = None
    psychopedagogical_evaluation_year: Optional[int] = None

# Customer schemas

class CustomerList(BaseModel):
    page: Optional[int] = None
    identification_number: Optional[str] = None
    names: Optional[str] = None
    company_name: Optional[str] = None
    per_page: int = 10

class StoreCustomer(BaseModel):
    country_id: Optional[int] = None
    region_id: Optional[int] = None
    commune_id: Optional[int] = None
    package_id: Optional[int] = None
    bill_or_ticket_id: Optional[int] = None
    identification_number: Optional[str] = None
    names: Optional[str] = None
    lastnames: Optional[str] = None
    address: Optional[str] = None
    company_name: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None
    license_time: Optional[date] = None
    password: Optional[str] = None
    rol_id: Optional[int] = None
    schools: Optional[List[str]] = None

    @field_validator("license_time", mode="before")
    @classmethod
    def _license_time_empty_to_none_store(cls, v: Any) -> Any:
        return _empty_str_to_none(v)

class UpdateCustomer(BaseModel):
    country_id: Optional[int] = None
    region_id: Optional[int] = None
    commune_id: Optional[int] = None
    package_id: Optional[int] = None
    bill_or_ticket_id: Optional[int] = None
    identification_number: Optional[str] = None
    names: Optional[str] = None
    lastnames: Optional[str] = None
    address: Optional[str] = None
    company_name: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None
    license_time: Optional[date] = None
    schools: Optional[List[str]] = None

    @field_validator("license_time", mode="before")
    @classmethod
    def _license_time_empty_to_none_update(cls, v: Any) -> Any:
        return _empty_str_to_none(v)


# Professional schemas

class ProfessionalList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    identification_number: Optional[str] = None
    names: Optional[str] = None
    school_id: Optional[int] = None
    period_year: Optional[int] = None

class StoreProfessional(BaseModel):
    identification_number: str
    names: str
    lastnames: str
    email: str
    birth_date: str
    address: str
    phone: str
    rol_id: int
    password: str
    school_id: Optional[int] = None
    period_year: Optional[int] = None
    course_id: Optional[List[int]] = None
    teaching_id: Optional[List[int]] = None
    career_type_id: Optional[int] = None

class UpdateProfessional(BaseModel):
    rol_id: Optional[int] = None
    identification_number: Optional[str] = None
    names: Optional[str] = None
    lastnames: Optional[str] = None
    email: Optional[str] = None
    birth_date: Optional[str] = None
    address: Optional[str] = None
    phone: Optional[str] = None
    school_id: Optional[int] = None
    period_year: Optional[int] = None
    course_id: Optional[List[int]] = None
    teaching_id: Optional[List[int]] = None
    career_type_id: Optional[int] = None

class StoreProfessionalTeachingCourse(BaseModel):
    """Asignar profesional a enseñanza/curso (una fila en professionals_teachings_courses)."""
    professional_id: int
    teaching_id: int
    course_id: int
    teacher_type_id: Optional[int] = None
    career_type_id: Optional[int] = None
    subject: Optional[str] = None

class UpdateProfessionalTeachingCourse(BaseModel):
    """Editar asignación profesional-enseñanza-curso (todos opcionales)."""
    professional_id: Optional[int] = None
    teaching_id: Optional[int] = None
    course_id: Optional[int] = None
    teacher_type_id: Optional[int] = None
    subject: Optional[str] = None
    specialty: Optional[str] = None
    career_type_id: Optional[int] = None
    deleted_status_id: Optional[int] = None


# Students-Professionals (students_professionals)

class StoreStudentProfessional(BaseModel):
    student_id: int
    professional_id: int
    career_type_id: Optional[int] = None
    hours: Optional[int] = None

class UpdateStudentProfessional(BaseModel):
    student_id: Optional[int] = None
    professional_id: Optional[int] = None
    career_type_id: Optional[int] = None
    hours: Optional[int] = None


# Document Alerts (document_alerts)

class StoreDocumentAlert(BaseModel):
    student_id: int
    professional_id: int
    document_id: int
    must_be_finish_date: Optional[str] = None  # YYYY-MM-DD o ISO
    document_uploaded_date: Optional[str] = None

class UpdateDocumentAlert(BaseModel):
    student_id: Optional[int] = None
    professional_id: Optional[int] = None
    document_id: Optional[int] = None
    must_be_finish_date: Optional[str] = None
    document_uploaded_date: Optional[str] = None


# Document 20: Community Education Support Program (CESP)

class CespGuardianSchema(BaseModel):
    guardian_id: Optional[int] = None
    name: Optional[str] = None
    identification_number: Optional[str] = None
    family_member_id: Optional[int] = None
    address: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None
    is_emergency_contact: Optional[int] = 0
    is_guardian: Optional[int] = 1

class CespParticipantProfessionalSchema(BaseModel):
    professional_id: int
    professional_role: Optional[str] = None

class CespSupportTeamMemberSchema(BaseModel):
    professional_id: int
    professional_role: Optional[str] = None
    support_roles: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None
    sort_order: Optional[int] = 0

class StoreCespDocument(BaseModel):
    student_id: int
    document_type_id: Optional[int] = 20
    elaboration_date: Optional[str] = None
    period_type_id: Optional[int] = 1
    pharmacological_treatment: Optional[str] = None  # 'yes' | 'no'
    external_specialists: Optional[str] = None  # 'yes' | 'no'
    profile_interaction: Optional[str] = None
    profile_involvement: Optional[str] = None
    profile_behavior_repertoire: Optional[str] = None
    profile_skills: Optional[str] = None
    profile_challenges: Optional[str] = None
    profile_support_needs: Optional[str] = None
    profile_interests: Optional[str] = None
    stressors_triggers: Optional[str] = None
    prevention_measures: Optional[str] = None
    suggestions_special: Optional[str] = None
    strategies_phase1_manifestations: Optional[str] = None
    strategies_phase1_strategies: Optional[str] = None
    strategies_phase2_manifestations: Optional[str] = None
    strategies_phase2_strategies: Optional[str] = None
    strategies_phase3_manifestations: Optional[str] = None
    strategies_phase3_strategies: Optional[str] = None
    strategies_phase4_manifestations: Optional[str] = None
    strategies_phase4_strategies: Optional[str] = None
    guardians: Optional[List[CespGuardianSchema]] = None
    participant_professional: Optional[CespParticipantProfessionalSchema] = None
    support_team_members: Optional[List[CespSupportTeamMemberSchema]] = None

class UpdateCespDocument(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = None
    elaboration_date: Optional[str] = None
    period_type_id: Optional[int] = None
    pharmacological_treatment: Optional[str] = None
    external_specialists: Optional[str] = None
    profile_interaction: Optional[str] = None
    profile_involvement: Optional[str] = None
    profile_behavior_repertoire: Optional[str] = None
    profile_skills: Optional[str] = None
    profile_challenges: Optional[str] = None
    profile_support_needs: Optional[str] = None
    profile_interests: Optional[str] = None
    stressors_triggers: Optional[str] = None
    prevention_measures: Optional[str] = None
    suggestions_special: Optional[str] = None
    strategies_phase1_manifestations: Optional[str] = None
    strategies_phase1_strategies: Optional[str] = None
    strategies_phase2_manifestations: Optional[str] = None
    strategies_phase2_strategies: Optional[str] = None
    strategies_phase3_manifestations: Optional[str] = None
    strategies_phase3_strategies: Optional[str] = None
    strategies_phase4_manifestations: Optional[str] = None
    strategies_phase4_strategies: Optional[str] = None
    guardians: Optional[List[CespGuardianSchema]] = None
    participant_professional: Optional[CespParticipantProfessionalSchema] = None
    support_team_members: Optional[List[CespSupportTeamMemberSchema]] = None


# Package schemas

class PackageList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    package_name: Optional[str] = None

class StorePackage(BaseModel):
    package_name: str
    students_per_package: int
    professionals_per_package: int

class UpdatePackage(BaseModel):
    package_name: Optional[str] = None
    students_per_package: Optional[int] = None
    professionals_per_package: Optional[int] = None

# Special Educational Need schemas

class SpecialEducationalNeedList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    special_educational_needs: Optional[str] = None
    special_educational_need_type_id: Optional[int] = None

class StoreSpecialEducationalNeed(BaseModel):
    special_educational_need_type_id: Optional[int] = None
    special_educational_needs: str
    school_id: Optional[int] = None

class UpdateSpecialEducationalNeed(BaseModel):
    special_educational_need_type_id: Optional[int] = None
    special_educational_needs: Optional[str] = None
    school_id: Optional[int] = None

# Diagnosis Summary schemas (cupos por NEE, curso y año)

class DiagnosisSummaryList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    school_id: Optional[int] = None
    special_educational_need_id: Optional[int] = None
    course_id: Optional[int] = None
    year_index: Optional[int] = None

class StoreDiagnosisSummary(BaseModel):
    school_id: Optional[int] = None
    special_educational_need_id: int
    course_id: int
    year_index: int = 0  # 0 = 1er año, 1 = 2do año
    available_slots: int = 0
    occupied_slots: int = 0

class UpdateDiagnosisSummary(BaseModel):
    school_id: Optional[int] = None
    special_educational_need_id: Optional[int] = None
    course_id: Optional[int] = None
    year_index: Optional[int] = None
    available_slots: Optional[int] = None
    occupied_slots: Optional[int] = None

# Document Type schemas

class DocumentTypeList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    document: Optional[str] = None

class StoreDocumentType(BaseModel):
    document_type_id: int
    document: str

class UpdateDocumentType(BaseModel):
    document_type_id: Optional[int] = None
    document: Optional[str] = None

# Message schemas

class MessageList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    subject: Optional[str] = None
    message_type_id: Optional[int] = None

class StoreMessage(BaseModel):
    message_type_id: int
    response_id: Optional[int] = None
    message_response_id: Optional[int] = None
    subject: str
    message: str

class UpdateMessage(BaseModel):
    message_type_id: Optional[int] = None
    response_id: Optional[int] = None
    message_response_id: Optional[int] = None
    subject: Optional[str] = None
    message: Optional[str] = None

# Action Incident schemas

class ActionIncidentList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    student_id: Optional[int] = None
    title: Optional[str] = None

class StoreActionIncident(BaseModel):
    student_id: int
    professional_id: Optional[int] = None
    action_incident_type_id: int
    status_id: Optional[int] = None
    title: str
    incident_date: Optional[str] = None
    incident_time: Optional[str] = None
    background: Optional[str] = None
    conduct: Optional[str] = None
    consequences: Optional[str] = None
    recommendations: Optional[str] = None

class UpdateActionIncident(BaseModel):
    student_id: Optional[int] = None
    professional_id: Optional[int] = None
    action_incident_type_id: Optional[int] = None
    status_id: Optional[int] = None
    title: Optional[str] = None
    incident_date: Optional[str] = None
    incident_time: Optional[str] = None
    background: Optional[str] = None
    conduct: Optional[str] = None
    consequences: Optional[str] = None
    recommendations: Optional[str] = None

# Meeting schemas
# Download schemas

class DownloadList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    title: Optional[str] = None
    download_type_id: Optional[int] = None

class StoreDownload(BaseModel):
    download_type_id: int
    title: str
    description: Optional[str] = None
    url: str
    tag: Optional[str] = None
    quantity: Optional[str] = None

class UpdateDownload(BaseModel):
    download_type_id: Optional[int] = None
    title: Optional[str] = None
    description: Optional[str] = None
    url: Optional[str] = None
    tag: Optional[str] = None
    quantity: Optional[str] = None

# Video schemas

class VideoList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    title: Optional[str] = None

class StoreVideo(BaseModel):
    title: str
    url: str

class UpdateVideo(BaseModel):
    title: Optional[str] = None
    url: Optional[str] = None

# Career Type schemas

class CareerTypeList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    career_type: Optional[str] = None

class StoreCareerType(BaseModel):
    career_type: str

class UpdateCareerType(BaseModel):
    career_type: Optional[str] = None

# FAQ schemas

class FaqList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    question: Optional[str] = None

class StoreFaq(BaseModel):
    question: str
    answer: str

class UpdateFaq(BaseModel):
    question: Optional[str] = None
    answer: Optional[str] = None

# Contact schemas

class ContactList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    names: Optional[str] = None
    subject_type_id: Optional[int] = None
    schedule_type_id: Optional[int] = None

class StoreContact(BaseModel):
    subject_type_id: int
    schedule_type_id: int
    names: str
    lastnames: str
    email: str
    celphone: Optional[str] = None
    message: str

class UpdateContact(BaseModel):
    subject_type_id: Optional[int] = None
    schedule_type_id: Optional[int] = None
    names: Optional[str] = None
    lastnames: Optional[str] = None
    email: Optional[str] = None
    celphone: Optional[str] = None
    message: Optional[str] = None

# Health Evaluation schemas

class StoreFamilyReport(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = 7
    version: Optional[int] = 1
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_social_name: Optional[str] = None
    student_born_date: Optional[str] = None
    student_age: Optional[str] = None
    student_course: Optional[str] = None
    student_school: Optional[str] = None
    professional_id: Optional[int] = None
    professional_identification_number: Optional[str] = None
    professional_social_name: Optional[str] = None
    professional_role: Optional[str] = None
    professional_phone: Optional[str] = None
    professional_email: Optional[str] = None
    report_delivery_date: Optional[str] = None
    receiver_full_name: Optional[str] = None
    receiver_identification_number: Optional[str] = None
    receiver_social_name: Optional[str] = None
    receiver_phone: Optional[str] = None
    receiver_email: Optional[str] = None
    receiver_relationship: Optional[str] = None
    receiver_presence_of: Optional[str] = None
    guardian_type: Optional[str] = None  # 'primary', 'substitute'
    has_power_of_attorney: Optional[str] = None  # 'yes', 'no'
    evaluation_type: Optional[str] = None  # 'admission', 'revaluation'
    evaluation_date: Optional[str] = None
    applied_instruments: Optional[str] = None
    diagnosis: Optional[str] = None
    pedagogical_strengths: Optional[str] = None
    pedagogical_support_needs: Optional[str] = None
    social_affective_strengths: Optional[str] = None
    social_affective_support_needs: Optional[str] = None
    health_strengths: Optional[str] = None
    health_support_needs: Optional[str] = None
    collaborative_work: Optional[str] = None
    home_support: Optional[str] = None
    agreements_commitments: Optional[str] = None
    evaluation_date_1: Optional[str] = None
    evaluation_date_2: Optional[str] = None
    evaluation_date_3: Optional[str] = None

class UpdateFamilyReport(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = None
    version: Optional[int] = None
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_social_name: Optional[str] = None
    student_born_date: Optional[str] = None
    student_age: Optional[str] = None
    student_course: Optional[str] = None
    student_school: Optional[str] = None
    professional_id: Optional[int] = None
    professional_identification_number: Optional[str] = None
    professional_social_name: Optional[str] = None
    professional_role: Optional[str] = None
    professional_phone: Optional[str] = None
    professional_email: Optional[str] = None
    report_delivery_date: Optional[str] = None
    receiver_full_name: Optional[str] = None
    receiver_identification_number: Optional[str] = None
    receiver_social_name: Optional[str] = None
    receiver_phone: Optional[str] = None
    receiver_email: Optional[str] = None
    receiver_relationship: Optional[str] = None
    receiver_presence_of: Optional[str] = None
    guardian_type: Optional[str] = None
    has_power_of_attorney: Optional[str] = None
    evaluation_type: Optional[str] = None
    evaluation_date: Optional[str] = None
    applied_instruments: Optional[str] = None
    diagnosis: Optional[str] = None
    pedagogical_strengths: Optional[str] = None
    pedagogical_support_needs: Optional[str] = None
    social_affective_strengths: Optional[str] = None
    social_affective_support_needs: Optional[str] = None
    health_strengths: Optional[str] = None
    health_support_needs: Optional[str] = None
    collaborative_work: Optional[str] = None
    home_support: Optional[str] = None
    agreements_commitments: Optional[str] = None
    evaluation_date_1: Optional[str] = None
    evaluation_date_2: Optional[str] = None
    evaluation_date_3: Optional[str] = None

class FamilyReportList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10

class StoreInterconsultation(BaseModel):
    student_id: int
    document_type_id: Optional[int] = 24
    full_name: Optional[str] = None
    gender_id: Optional[int] = None
    identification_number: Optional[str] = None
    born_date: Optional[str] = None
    age: Optional[str] = None
    nationality_id: Optional[int] = None
    native_language: Optional[str] = None
    language_usually_used: Optional[str] = None
    address: Optional[str] = None
    region_id: Optional[int] = None
    commune_id: Optional[int] = None
    city: Optional[str] = None
    responsible_id: Optional[int] = None
    contact_phone: Optional[str] = None
    contact_email: Optional[str] = None
    educational_establishment: Optional[str] = None
    course_level: Optional[str] = None
    program_type_id: Optional[int] = None
    establishment_address: Optional[str] = None
    establishment_commune: Optional[str] = None
    establishment_phone: Optional[str] = None
    establishment_email: Optional[str] = None
    additional_information_id: Optional[int] = None
    question_to_answer: Optional[str] = None
    attached_documents: Optional[str] = None
    referring_professional: Optional[str] = None
    reception_date: Optional[str] = None
    evaluation_summary: Optional[str] = None
    indications_support: Optional[str] = None
    professional_id: Optional[int] = None
    professional_identification_number: Optional[str] = None
    professional_registration_number: Optional[str] = None
    professional_specialty: Optional[str] = None
    procedence_id: Optional[int] = None
    procedence_other: Optional[str] = None
    professional_contact_phone: Optional[str] = None
    evaluation_date: Optional[str] = None
    required_new_control_id: Optional[int] = None
    new_control_date: Optional[str] = None

class UpdateInterconsultation(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = None
    full_name: Optional[str] = None
    gender_id: Optional[int] = None
    identification_number: Optional[str] = None
    born_date: Optional[str] = None
    age: Optional[str] = None
    nationality_id: Optional[int] = None
    native_language: Optional[str] = None
    language_usually_used: Optional[str] = None
    address: Optional[str] = None
    region_id: Optional[int] = None
    commune_id: Optional[int] = None
    city: Optional[str] = None
    responsible_id: Optional[int] = None
    contact_phone: Optional[str] = None
    contact_email: Optional[str] = None
    educational_establishment: Optional[str] = None
    course_level: Optional[str] = None
    program_type_id: Optional[int] = None
    establishment_address: Optional[str] = None
    establishment_commune: Optional[str] = None
    establishment_phone: Optional[str] = None
    establishment_email: Optional[str] = None
    additional_information_id: Optional[int] = None
    question_to_answer: Optional[str] = None
    attached_documents: Optional[str] = None
    referring_professional: Optional[str] = None
    reception_date: Optional[str] = None
    evaluation_summary: Optional[str] = None
    indications_support: Optional[str] = None
    professional_id: Optional[int] = None
    professional_identification_number: Optional[str] = None
    professional_registration_number: Optional[str] = None
    professional_specialty: Optional[str] = None
    procedence_id: Optional[int] = None
    procedence_other: Optional[str] = None
    professional_contact_phone: Optional[str] = None
    evaluation_date: Optional[str] = None
    required_new_control_id: Optional[int] = None
    new_control_date: Optional[str] = None

class InterconsultationList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10

class StoreGuardianAttendanceCertificate(BaseModel):
    """Document 25 - Certificado de asistencia del apoderado (Ley TEA)."""
    student_id: int
    document_type_id: Optional[int] = 25
    professional_id: Optional[int] = None
    certificate_date: Optional[str] = None  # YYYY-MM-DD
    start_time: Optional[str] = None        # HH:MM or HH:MM:SS
    end_time: Optional[str] = None         # HH:MM or HH:MM:SS

class UpdateGuardianAttendanceCertificate(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = None
    professional_id: Optional[int] = None
    certificate_date: Optional[str] = None
    start_time: Optional[str] = None
    end_time: Optional[str] = None

class StoreCoordinatorsCourse(BaseModel):
    """Tabla coordinators_courses: coordinador asignado a curso por colegio. school_id se obtiene de la sesión."""
    course_id: int
    professional_id: int
    coordinator_type_id: int
    phone: Optional[str] = None
    email: Optional[str] = None

class UpdateCoordinatorsCourse(BaseModel):
    school_id: Optional[int] = None
    course_id: Optional[int] = None
    professional_id: Optional[int] = None
    coordinator_type_id: Optional[int] = None
    phone: Optional[str] = None
    email: Optional[str] = None

class StoreMeetingSchedulaling(BaseModel):
    """Tabla meeting_schedualings. school_id se obtiene de la sesión."""
    course_id: int
    period_id: Optional[int] = None
    meeting_date: Optional[str] = None  # YYYY-MM-DD
    meeting_time: Optional[str] = None

class UpdateMeetingSchedulaling(BaseModel):
    school_id: Optional[int] = None
    course_id: Optional[int] = None
    period_id: Optional[int] = None
    meeting_date: Optional[str] = None  # YYYY-MM-DD
    meeting_time: Optional[str] = None

class StoreMeetingSchedualingAgreement(BaseModel):
    """Tabla meeting_schedualing_agreements."""
    meeting_schedualing_id: int
    agreements: Optional[str] = None

class UpdateMeetingSchedualingAgreement(BaseModel):
    meeting_schedualing_id: Optional[int] = None
    agreements: Optional[str] = None

class StoreMeetingSchedualingRegisterProfessional(BaseModel):
    """Tabla meeting_schedualing_register_professionals."""
    meeting_schedualing_register_id: int
    professional_id: int

class UpdateMeetingSchedualingRegisterProfessional(BaseModel):
    meeting_schedualing_register_id: Optional[int] = None
    professional_id: Optional[int] = None

class SyncMeetingSchedualingRegisterProfessionals(BaseModel):
    """Lista de professional_id que debe quedar para ese register. Los que no estén se borran (lógico)."""
    professional_ids: list[int] = []

class StoreDiversifiedStrategy(BaseModel):
    """Tabla diversified_strategies (Diversified Strategies)."""
    course_id: int
    planning_learning_styles: Optional[str] = None
    planning_strengths: Optional[str] = None
    planning_support_needs: Optional[str] = None

class UpdateDiversifiedStrategy(BaseModel):
    course_id: Optional[int] = None
    planning_learning_styles: Optional[str] = None
    planning_strengths: Optional[str] = None
    planning_support_needs: Optional[str] = None

class StoreRegularTeacherDiversifiedStrategy(BaseModel):
    """Tabla regular_teacher_diversified_strategies. school_id del body o de la sesión."""
    model_config = ConfigDict(populate_by_name=True)

    school_id: Optional[int] = None
    course_id: int
    subject_id: Optional[int] = None
    strategy: Optional[str] = None
    period: Optional[str] = None
    period_id: Optional[int] = Field(None, validation_alias=AliasChoices("period_id", "periodId"))
    criteria: Optional[str] = None

class UpdateRegularTeacherDiversifiedStrategy(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    school_id: Optional[int] = None
    course_id: Optional[int] = None
    subject_id: Optional[int] = None
    strategy: Optional[str] = None
    period: Optional[str] = None
    period_id: Optional[int] = Field(None, validation_alias=AliasChoices("period_id", "periodId"))
    criteria: Optional[str] = None

class StoreSubject(BaseModel):
    """Tabla subjects. school_id se puede enviar o tomar de la sesión."""
    school_id: Optional[int] = None
    subject: Optional[str] = None

class UpdateSubject(BaseModel):
    school_id: Optional[int] = None
    subject: Optional[str] = None

class StoreCollaborativeWork(BaseModel):
    """Tabla collaborative_works. school_id puede venir del body o de la sesión."""
    school_id: Optional[int] = None
    course_id: Optional[int] = None
    planning_collab_co_teaching: Optional[str] = None
    planning_collab_assistants: Optional[str] = None
    planning_collab_students: Optional[str] = None
    planning_collab_family: Optional[str] = None
    planning_collab_community: Optional[str] = None
    planning_observations: Optional[str] = None

class UpdateCollaborativeWork(BaseModel):
    school_id: Optional[int] = None
    course_id: Optional[int] = None
    planning_collab_co_teaching: Optional[str] = None
    planning_collab_assistants: Optional[str] = None
    planning_collab_students: Optional[str] = None
    planning_collab_family: Optional[str] = None
    planning_collab_community: Optional[str] = None
    planning_observations: Optional[str] = None

class StoreSupportOrganization(BaseModel):
    """Tabla support_organizations. school_id del body o de la sesión."""
    school_id: Optional[int] = None
    course_id: Optional[int] = None
    subject_id: Optional[int] = None
    hours_support_regular_classroom: Optional[str] = None
    hours_support_outside_classroom: Optional[str] = None
    specialized_support_types: Optional[str] = None

class UpdateSupportOrganization(BaseModel):
    school_id: Optional[int] = None
    course_id: Optional[int] = None
    subject_id: Optional[int] = None
    hours_support_regular_classroom: Optional[str] = None
    hours_support_outside_classroom: Optional[str] = None
    specialized_support_types: Optional[str] = None

class StoreCourseDiversityResponse(BaseModel):
    """Tabla course_diversity_responses. Upsert por (course_id, diversity_criterion_id). Incluye observations (course_diversity_observations)."""
    course_id: int
    diversity_criterion_id: int
    criterion_selected: Optional[bool] = False
    diversity_strategy_option_id: Optional[int] = None
    how_text: Optional[str] = None
    student_ids: Optional[List[int]] = None
    observations: Optional[str] = None

class UpdateCourseDiversityResponse(BaseModel):
    criterion_selected: Optional[bool] = None
    diversity_strategy_option_id: Optional[int] = None
    how_text: Optional[str] = None
    student_ids: Optional[List[int]] = None

class StoreCourseDiversityObservations(BaseModel):
    """Tabla course_diversity_observations. Una fila por course_id."""
    course_id: int
    observations: Optional[str] = None


# ---------------------------------------------------------------------------
# Ajustes (adjustment_aspects, course_adjustments, course_adjustment_students)
# ---------------------------------------------------------------------------

class StoreCourseAdjustment(BaseModel):
    """Upsert por (course_id, adjustment_aspect_id)."""
    course_id: int
    adjustment_aspect_id: int
    other_aspect_text: Optional[str] = None
    value: Optional[str] = None
    student_ids: Optional[List[int]] = None

class UpdateCourseAdjustment(BaseModel):
    other_aspect_text: Optional[str] = None
    value: Optional[str] = None
    student_ids: Optional[List[int]] = None


# ---------------------------------------------------------------------------
# Adecuaciones curriculares (curricular_adequacy_types, course_curricular_adequacies)
# ---------------------------------------------------------------------------

class StoreCourseCurricularAdequacy(BaseModel):
    """Upsert por (course_id, curricular_adequacy_type_id)."""
    course_id: int
    curricular_adequacy_type_id: int
    applied: Optional[bool] = False
    scope_text: Optional[str] = None
    strategies_text: Optional[str] = None
    subject_ids: Optional[List[int]] = None
    student_ids: Optional[List[int]] = None

class UpdateCourseCurricularAdequacy(BaseModel):
    applied: Optional[bool] = None
    scope_text: Optional[str] = None
    strategies_text: Optional[str] = None
    subject_ids: Optional[List[int]] = None
    student_ids: Optional[List[int]] = None


# ---------------------------------------------------------------------------
# Plan de Apoyo Individual (course_individual_supports)
# ---------------------------------------------------------------------------

class StoreCourseIndividualSupport(BaseModel):
    """Crear o actualizar un apoyo individual por curso (área = support_area_id)."""
    course_id: int
    support_area_id: Optional[int] = None
    horario: Optional[str] = None
    fecha_inicio: Optional[str] = None  # ISO date string
    fecha_termino: Optional[str] = None
    observations: Optional[str] = None
    student_ids: Optional[List[int]] = None

class UpdateCourseIndividualSupport(BaseModel):
    support_area_id: Optional[int] = None
    horario: Optional[str] = None
    fecha_inicio: Optional[str] = None
    fecha_termino: Optional[str] = None
    observations: Optional[str] = None
    student_ids: Optional[List[int]] = None


# ---------------------------------------------------------------------------
# Card 2: Registro de apoyos (course_record_support, course_record_support_students, interventions)
# ---------------------------------------------------------------------------

class StoreCourseRecordSupport(BaseModel):
    """Guardar registro por curso y área: objetivos de aprendizaje + estudiantes."""
    course_id: int
    support_area_id: int
    learning_objectives: Optional[str] = None
    student_ids: Optional[List[int]] = None

class UpdateCourseRecordSupport(BaseModel):
    learning_objectives: Optional[str] = None
    student_ids: Optional[List[int]] = None

class StoreCourseRecordSupportIntervention(BaseModel):
    """Crear intervención 'Ingresar apoyo'."""
    course_id: int
    support_area_id: int
    date: str  # ISO date
    pedagogical_hours: Optional[float] = None
    place: Optional[str] = None
    professional_id: Optional[int] = None
    activities_description: Optional[str] = None

class UpdateCourseRecordSupportIntervention(BaseModel):
    date: Optional[str] = None
    pedagogical_hours: Optional[float] = None
    place: Optional[str] = None
    professional_id: Optional[int] = None
    activities_description: Optional[str] = None


# ---------------------------------------------------------------------------
# Card 3: Registro de logros de aprendizaje (course_learning_achievements)
# ---------------------------------------------------------------------------

class StoreCourseLearningAchievement(BaseModel):
    """Upsert por (course_id, student_id, period_id). period_id: 1, 2 o 3."""
    course_id: int
    student_id: int
    period_id: int  # 1 = 1er período, 2 = 2do, 3 = 3er
    achievements: Optional[str] = None
    comments: Optional[str] = None

class UpdateCourseLearningAchievement(BaseModel):
    achievements: Optional[str] = None
    comments: Optional[str] = None


# ---------------------------------------------------------------------------
# b) Pestaña 3: Registro de acciones del profesor (observaciones 1 por materia, actividades varias)
# ---------------------------------------------------------------------------

class StoreCourseTeacherRecordObservation(BaseModel):
    """Observaciones por asignatura (1 por course_id, subject_id)."""
    course_id: int
    subject_id: int
    observations: Optional[str] = None

class UpdateCourseTeacherRecordObservation(BaseModel):
    observations: Optional[str] = None

class StoreCourseTeacherRecordActivity(BaseModel):
    """Actividad registrada por asignatura (varias por materia)."""
    course_id: int
    subject_id: int
    date: str  # ISO date
    pedagogical_hours: Optional[float] = 0
    teacher_names: Optional[List[str]] = None  # ["Juan Pérez", "María López"]
    description: Optional[str] = None

class UpdateCourseTeacherRecordActivity(BaseModel):
    date: Optional[str] = None
    pedagogical_hours: Optional[float] = None
    teacher_names: Optional[List[str]] = None
    description: Optional[str] = None


# ---------------------------------------------------------------------------
# IV. Registro de actividades (familia/comunidad)
# ---------------------------------------------------------------------------

class CourseActivityAttendee(BaseModel):
    id: Optional[int] = 0
    name: str
    # 1 = Apoderado, 2 = Profesional del establecimiento (course_activity_records.attendees JSON)
    participant_type: Optional[int] = Field(None, ge=1, le=2, description="1 Apoderado, 2 Profesional")
    rut: Optional[str] = None  # V.3 otras reuniones: RUT en JSON de asistentes
    # Plantilla IV: columna «apoderado o profesional» / «Teléfono-Mail»
    role: Optional[str] = None
    tipo: Optional[str] = None  # sinónimo de role (UI en español); se unifica al guardar en JSON como role
    phone: Optional[str] = None
    telefono: Optional[str] = None  # sinónimo de phone
    email: Optional[str] = None
    mail: Optional[str] = None  # sinónimo de email

class StoreCourseActivityRecord(BaseModel):
    course_id: int
    section: str = "family"
    date: Optional[str] = None  # YYYY-MM-DD
    attendees: Optional[List[CourseActivityAttendee]] = None
    objectives: Optional[str] = None
    activities: Optional[str] = None
    agreements: Optional[str] = None
    results: Optional[str] = None

    @field_validator("section", mode="before")
    @classmethod
    def _coerce_course_activity_section(cls, v: Any) -> str:
        from app.backend.classes.course_activity_record_class import normalize_course_activity_section

        return normalize_course_activity_section(v)

class UpdateCourseActivityRecord(BaseModel):
    section: Optional[str] = None
    date: Optional[str] = None
    attendees: Optional[List[CourseActivityAttendee]] = None
    objectives: Optional[str] = None
    activities: Optional[str] = None
    agreements: Optional[str] = None
    results: Optional[str] = None

    @field_validator("section", mode="before")
    @classmethod
    def _coerce_course_activity_section(cls, v: Any) -> Any:
        if v is None:
            return None
        from app.backend.classes.course_activity_record_class import normalize_course_activity_section

        return normalize_course_activity_section(v)


# ---------------------------------------------------------------------------
# c) Estrategias y procedimientos de evaluación (eval_diversity_types, course_eval_diversity, observations)
# ---------------------------------------------------------------------------

class StoreCourseEvalDiversity(BaseModel):
    """Upsert por (course_id, eval_diversity_type_id)."""
    course_id: int
    eval_diversity_type_id: int
    strategies_text: Optional[str] = None
    observations: Optional[str] = None

class UpdateCourseEvalDiversity(BaseModel):
    strategies_text: Optional[str] = None

class StoreCourseEvalDiversityObservations(BaseModel):
    """Observaciones de la sección c) — una por curso."""
    course_id: int
    observations: Optional[str] = None


# ---------------------------------------------------------------------------
# 5. Estrategias de trabajo con la familia y con la comunidad
# ---------------------------------------------------------------------------

class StoreCourseFamilyCommunity(BaseModel):
    """Upsert por (course_id, family_community_strategy_type_id)."""
    course_id: int
    family_community_strategy_type_id: int
    descripcion: Optional[str] = None
    seguimiento: Optional[str] = None
    evaluacion: Optional[str] = None
    observations: Optional[str] = None

class UpdateCourseFamilyCommunity(BaseModel):
    descripcion: Optional[str] = None
    seguimiento: Optional[str] = None
    evaluacion: Optional[str] = None

class StoreCourseFamilyCommunityObservations(BaseModel):
    """Observaciones de la sección 5 — una por curso."""
    course_id: int
    observations: Optional[str] = None


# ---------------------------------------------------------------------------
# Support areas (support_areas)
# ---------------------------------------------------------------------------

class StoreSupportArea(BaseModel):
    support_area: Optional[str] = None

class UpdateSupportArea(BaseModel):
    support_area: Optional[str] = None


# ---------------------------------------------------------------------------
# dynamic_forms (formularios dinámicos — JSON fields)
# ---------------------------------------------------------------------------

class DynamicFormFieldOptionSchema(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    label: str
    value: str

class DynamicFormFieldSchema(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    id: Optional[str] = None
    question: str
    fieldType: str = Field(validation_alias=AliasChoices("fieldType", "field_type"))
    options: List[DynamicFormFieldOptionSchema] = Field(default_factory=list)
    required: bool = False

class StoreDynamicForm(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    name: str
    description: Optional[str] = ""
    fields: List[DynamicFormFieldSchema]
    periodYear: int = Field(..., ge=2000, le=2100, validation_alias=AliasChoices("periodYear", "period_year"))
    courseId: int = Field(..., ge=1, validation_alias=AliasChoices("courseId", "course_id"))
    notifyStudentIds: Optional[List[int]] = Field(
        None, validation_alias=AliasChoices("notifyStudentIds", "notify_student_ids")
    )

class UpdateDynamicForm(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    name: Optional[str] = None
    description: Optional[str] = None
    fields: Optional[List[DynamicFormFieldSchema]] = None
    periodYear: int = Field(..., ge=2000, le=2100, validation_alias=AliasChoices("periodYear", "period_year"))
    courseId: int = Field(..., ge=1, validation_alias=AliasChoices("courseId", "course_id"))
    notifyStudentIds: Optional[List[int]] = Field(
        None, validation_alias=AliasChoices("notifyStudentIds", "notify_student_ids")
    )

class SubmitDynamicFormAnswers(BaseModel):
    """Envío de respuestas del formulario para un estudiante."""

    model_config = ConfigDict(populate_by_name=True)

    studentId: int = Field(..., ge=1, validation_alias=AliasChoices("studentId", "student_id"))
    answers: Dict[str, Any] = Field(default_factory=dict)

class ResendFormWhatsApp(BaseModel):
    """Reenviar plantilla WhatsApp al apoderado (estudiante en espera)."""

    model_config = ConfigDict(populate_by_name=True)

    studentId: int = Field(..., ge=1, validation_alias=AliasChoices("studentId", "student_id"))


# ---------------------------------------------------------------------------
# informal_tests (plantillas de pruebas informales por colegio)
# ---------------------------------------------------------------------------

class InformalTestQuestionOptionSchema(BaseModel):
    label: str
    value: str

class InformalTestQuestionSchema(BaseModel):
    id: Optional[int] = None
    question_text: str
    question_type: str  # short_text|long_text|single_choice|multiple_choice|number|date
    required: bool = False
    options: List[InformalTestQuestionOptionSchema] = Field(default_factory=list)

class StoreInformalTestTemplate(BaseModel):
    name: str
    description: Optional[str] = None
    questions: List[InformalTestQuestionSchema] = Field(default_factory=list)
    student_id: Optional[int] = None

class UpdateInformalTestTemplate(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    questions: Optional[List[InformalTestQuestionSchema]] = None

class SubmitInformalTestTemplateAnswers(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    student_id: int = Field(..., ge=1, validation_alias=AliasChoices("student_id", "studentId"))
    answers: Dict[str, Any] = Field(default_factory=dict)


# ---------------------------------------------------------------------------
# differentiated_strategies_implementations
# ---------------------------------------------------------------------------

class StoreDifferentiatedStrategiesImplementation(BaseModel):
    period_id: Optional[int] = None
    actions_taken: Optional[str] = None
    applied_strategies: Optional[str] = None

class UpdateDifferentiatedStrategiesImplementation(BaseModel):
    period_id: Optional[int] = None
    actions_taken: Optional[str] = None
    applied_strategies: Optional[str] = None

class StoreHealthEvaluation(BaseModel):
    student_id: Optional[int] = None
    gender_id: Optional[int] = None
    nationality_id: Optional[int] = None
    consultation_reason_id: Optional[int] = None
    profesional_id: Optional[int] = None
    procedence_id: Optional[int] = None
    full_name: Optional[str] = None
    identification_number: Optional[str] = None
    born_date: Optional[str] = None
    age: Optional[int] = None
    native_language: Optional[str] = None
    language_usually_used: Optional[str] = None
    consultation_reason_detail: Optional[str] = None
    professional_identification_number: Optional[str] = None
    professional_registration_number: Optional[str] = None
    professional_specialty: Optional[str] = None
    procedence_other: Optional[str] = None
    professional_contact: Optional[str] = None
    evaluation_date: Optional[str] = None
    reevaluation_date: Optional[str] = None
    general_assessment: Optional[str] = None
    diagnosis: Optional[str] = None
    indications: Optional[str] = None


# Document 27: Psychopedagogical Evaluation Information

class PsychopedagogicalEvaluationScaleItem(BaseModel):
    scale_type: str  # 'pedagogical' | 'social_communicative'
    indicator_number: int  # 1-10
    value: str  # '1', '2', '3', 'N/O'

class StorePsychopedagogicalEvaluationInfo(BaseModel):
    student_id: int
    social_name: Optional[str] = None
    age: Optional[str] = None
    evaluation_date: Optional[str] = None
    diagnosis: Optional[str] = None
    diagnosis_issue_date: Optional[str] = None
    admission_type: Optional[str] = None  # ingreso|reevaluacion|otro
    admission_type_other: Optional[str] = None
    instruments_applied: Optional[str] = None
    school_history_background: Optional[str] = None
    cognitive_analysis: Optional[str] = None
    cognitive_quantitative_matrix: Optional[str] = None
    cognitive_general_scales: Optional[str] = None
    personal_analysis: Optional[str] = None
    motor_analysis: Optional[str] = None  # alias moto_analysis aceptado en clase
    cognitive_synthesis: Optional[str] = None
    personal_synthesis: Optional[str] = None
    motor_synthesis: Optional[str] = None
    suggestions_to_school: Optional[str] = None
    suggestions_to_classroom_team: Optional[str] = None
    suggestions_to_student: Optional[str] = None
    suggestions_to_family: Optional[str] = None
    other_suggestions: Optional[str] = None
    conclusion: Optional[str] = None
    professional_id: Optional[int] = None
    professional_identification_number: Optional[str] = None
    professional_registration_number: Optional[str] = None
    professional_specialty: Optional[str] = None
    scales: Optional[List[PsychopedagogicalEvaluationScaleItem]] = None
    # Escalas en formato plano (frontend envía pedagogical_scale_1..10, social_communicative_scale_1..10)
    pedagogical_scale_1: Optional[str] = None
    pedagogical_scale_2: Optional[str] = None
    pedagogical_scale_3: Optional[str] = None
    pedagogical_scale_4: Optional[str] = None
    pedagogical_scale_5: Optional[str] = None
    pedagogical_scale_6: Optional[str] = None
    pedagogical_scale_7: Optional[str] = None
    pedagogical_scale_8: Optional[str] = None
    pedagogical_scale_9: Optional[str] = None
    pedagogical_scale_10: Optional[str] = None
    social_communicative_scale_1: Optional[str] = None
    social_communicative_scale_2: Optional[str] = None
    social_communicative_scale_3: Optional[str] = None
    social_communicative_scale_4: Optional[str] = None
    social_communicative_scale_5: Optional[str] = None
    social_communicative_scale_6: Optional[str] = None
    social_communicative_scale_7: Optional[str] = None
    social_communicative_scale_8: Optional[str] = None
    social_communicative_scale_9: Optional[str] = None
    social_communicative_scale_10: Optional[str] = None

class UpdatePsychopedagogicalEvaluationInfo(BaseModel):
    social_name: Optional[str] = None
    age: Optional[str] = None
    evaluation_date: Optional[str] = None
    diagnosis: Optional[str] = None
    diagnosis_issue_date: Optional[str] = None
    admission_type: Optional[str] = None
    admission_type_other: Optional[str] = None
    instruments_applied: Optional[str] = None
    school_history_background: Optional[str] = None
    cognitive_analysis: Optional[str] = None
    cognitive_quantitative_matrix: Optional[str] = None
    cognitive_general_scales: Optional[str] = None
    personal_analysis: Optional[str] = None
    motor_analysis: Optional[str] = None
    cognitive_synthesis: Optional[str] = None
    personal_synthesis: Optional[str] = None
    motor_synthesis: Optional[str] = None
    suggestions_to_school: Optional[str] = None
    suggestions_to_classroom_team: Optional[str] = None
    suggestions_to_student: Optional[str] = None
    suggestions_to_family: Optional[str] = None
    other_suggestions: Optional[str] = None
    conclusion: Optional[str] = None
    professional_id: Optional[int] = None
    professional_identification_number: Optional[str] = None
    professional_registration_number: Optional[str] = None
    professional_specialty: Optional[str] = None
    scales: Optional[List[PsychopedagogicalEvaluationScaleItem]] = None
    pedagogical_scale_1: Optional[str] = None
    pedagogical_scale_2: Optional[str] = None
    pedagogical_scale_3: Optional[str] = None
    pedagogical_scale_4: Optional[str] = None
    pedagogical_scale_5: Optional[str] = None
    pedagogical_scale_6: Optional[str] = None
    pedagogical_scale_7: Optional[str] = None
    pedagogical_scale_8: Optional[str] = None
    pedagogical_scale_9: Optional[str] = None
    pedagogical_scale_10: Optional[str] = None
    social_communicative_scale_1: Optional[str] = None
    social_communicative_scale_2: Optional[str] = None
    social_communicative_scale_3: Optional[str] = None
    social_communicative_scale_4: Optional[str] = None
    social_communicative_scale_5: Optional[str] = None
    social_communicative_scale_6: Optional[str] = None
    social_communicative_scale_7: Optional[str] = None
    social_communicative_scale_8: Optional[str] = None
    social_communicative_scale_9: Optional[str] = None
    social_communicative_scale_10: Optional[str] = None


# Document 29: Conners Teacher Abbreviated + Conduct

class ConnersTeacherScoreItem(BaseModel):
    item_index: int  # 1-10
    score: int  # 0-3

class ConnersConductResponseItem(BaseModel):
    item_index: int  # 1-18
    response: str  # n | p | b | m

class StoreConnersTeacherEvaluation(BaseModel):
    student_id: int
    evaluation_date: str  # YYYY-MM-DD
    evaluator_name: str = ''
    evaluation_type: str = 'ingreso'  # ingreso | reevaluacion
    comments_observations: Optional[str] = None
    total_score: Optional[int] = None  # 0-30
    scores: Optional[List[ConnersTeacherScoreItem]] = None  # 10 items
    conduct_responses: Optional[List[ConnersConductResponseItem]] = None  # 18 items

class UpdateConnersTeacherEvaluation(BaseModel):
    evaluation_date: Optional[str] = None
    evaluator_name: Optional[str] = None
    evaluation_type: Optional[str] = None
    comments_observations: Optional[str] = None
    total_score: Optional[int] = None
    scores: Optional[List[ConnersTeacherScoreItem]] = None
    conduct_responses: Optional[List[ConnersConductResponseItem]] = None


# Event schemas

class EventList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10

class StoreEvent(BaseModel):
    title: str
    color: Optional[str] = None
    start_date: datetime
    end_date: datetime
    description: Optional[str] = None

class UpdateEvent(BaseModel):
    title: Optional[str] = None
    color: Optional[str] = None
    start_date: Optional[datetime] = None
    end_date: Optional[datetime] = None
    description: Optional[str] = None

class BankDescriptionList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    school_id: int
    document_id: int
    question_number: int

class StoreBankDescription(BaseModel):
    school_id: int
    document_id: int
    question_number: int
    bank_description: str

class UpdateBankDescription(BaseModel):
    school_id: Optional[int] = None
    document_id: Optional[int] = None
    question_number: Optional[int] = None
    bank_description: Optional[str] = None

# Progress Status Students schemas (Documento 18)

class ProgressStatusStudentList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    student_id: Optional[int] = None
    school_id: Optional[int] = None

class StoreProgressStatusStudent(BaseModel):
    version_id: Optional[int] = None
    student_id: Optional[int] = None
    school_id: Optional[int] = None
    document_id: Optional[int] = 18  # Siempre 18 para progress status
    nee_id: Optional[int] = None
    course_id: Optional[int] = None
    guardian_relationship_id: Optional[int] = None
    period_id: Optional[int] = None
    responsible_professionals: Optional[str] = None  # IDs de profesionales separados por comas: "1,2,3"
    progress_date: Optional[str] = None  # Formato: "YYYY-MM-DD"
    
    # II. Estado de avance por área
    pedagogical_language: Optional[str] = None
    pedagogical_mathematics: Optional[str] = None
    psychopedagogical: Optional[str] = None
    speech_therapy: Optional[str] = None
    psychological: Optional[str] = None
    kinesiology: Optional[str] = None
    occupational_therapy: Optional[str] = None
    deaf_co_educator: Optional[str] = None
    
    # III. Síntesis, comentarios u observaciones
    synthesis_comments: Optional[str] = None
    
    # IV. Sugerencias
    suggestions_family: Optional[str] = None
    suggestions_establishment: Optional[str] = None
    
    # Archivo adjunto
    file: Optional[str] = None

class UpdateProgressStatusStudent(BaseModel):
    version_id: Optional[int] = None
    student_id: Optional[int] = None
    school_id: Optional[int] = None
    document_id: Optional[int] = None
    nee_id: Optional[int] = None
    course_id: Optional[int] = None
    guardian_relationship_id: Optional[int] = None
    period_id: Optional[int] = None
    responsible_professionals: Optional[List[int]] = None
    progress_date: Optional[str] = None
    
    # II. Estado de avance por área
    pedagogical_language: Optional[str] = None
    pedagogical_mathematics: Optional[str] = None
    psychopedagogical: Optional[str] = None
    speech_therapy: Optional[str] = None
    psychological: Optional[str] = None
    kinesiology: Optional[str] = None
    occupational_therapy: Optional[str] = None
    deaf_co_educator: Optional[str] = None
    
    # III. Síntesis, comentarios u observaciones
    synthesis_comments: Optional[str] = None
    
    # IV. Sugerencias
    suggestions_family: Optional[str] = None
    suggestions_establishment: Optional[str] = None
    
    # Archivo adjunto
    file: Optional[str] = None

# Individual Support Plans schemas (Plan de Apoyo Individual - Documento 22)

class IndividualSupportPlanProfessionalSchema(BaseModel):
    professional_id: Optional[int] = None
    career_type_id: Optional[int] = None
    registration_number: Optional[str] = None
    days_hours: Optional[str] = None
    from_date: Optional[str] = None  # Formato: "YYYY-MM-DD"
    to_date: Optional[str] = None  # Formato: "YYYY-MM-DD"
    support_modality: Optional[str] = None

class StoreIndividualSupportPlan(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = None
    school_id: Optional[int] = None
    period_id: Optional[int] = None
    
    # I. Identificación del/la estudiante
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_born_date: Optional[str] = None  # Formato: "YYYY-MM-DD"
    student_age: Optional[str] = None
    student_nee_id: Optional[int] = None
    student_school: Optional[str] = None
    student_course_id: Optional[int] = None
    elaboration_date: Optional[str] = None  # Formato: "YYYY-MM-DD"
    
    # II. Fortalezas del/la estudiante
    social_affective_strengths: Optional[str] = None
    cognitive_strengths: Optional[str] = None
    curricular_strengths: Optional[str] = None
    family_strengths: Optional[str] = None
    
    # III. Propuesta de intervención - Ed. Diferencial
    intervention_ed_diferencial: Optional[str] = None  # Objetivos separados por comas
    intervention_ed_diferencial_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Psicopedagogía
    intervention_psicopedagogia: Optional[str] = None  # Objetivos separados por comas
    intervention_psicopedagogia_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Fonoaudiología
    intervention_fonoaudiologia: Optional[str] = None  # Objetivos separados por comas
    intervention_fonoaudiologia_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Psicología
    intervention_psicologia: Optional[str] = None  # Objetivos separados por comas
    intervention_psicologia_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Terapia ocupacional
    intervention_terapia_ocupacional: Optional[str] = None  # Objetivos separados por comas
    intervention_terapia_ocupacional_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Kinesiología
    intervention_kinesiologia: Optional[str] = None  # Objetivos separados por comas
    intervention_kinesiologia_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Co-educador sordo
    intervention_coeducador_sordo: Optional[str] = None  # Objetivos separados por comas
    intervention_coeducador_sordo_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Int. lengua de señas
    intervention_int_lengua_senas: Optional[str] = None  # Objetivos separados por comas
    intervention_int_lengua_senas_strategies: Optional[str] = None
    
    # IV. Seguimiento del PAI
    follow_up_pai: Optional[str] = None
    
    # Profesionales asociados
    professionals: Optional[List[IndividualSupportPlanProfessionalSchema]] = None

class UpdateIndividualSupportPlan(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = None
    school_id: Optional[int] = None
    period_id: Optional[int] = None
    
    # I. Identificación del/la estudiante
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_born_date: Optional[str] = None  # Formato: "YYYY-MM-DD"
    student_age: Optional[str] = None
    student_nee_id: Optional[int] = None
    student_school: Optional[str] = None
    student_course_id: Optional[int] = None
    elaboration_date: Optional[str] = None  # Formato: "YYYY-MM-DD"
    
    # II. Fortalezas del/la estudiante
    social_affective_strengths: Optional[str] = None
    cognitive_strengths: Optional[str] = None
    curricular_strengths: Optional[str] = None
    family_strengths: Optional[str] = None
    
    # III. Propuesta de intervención - Ed. Diferencial
    intervention_ed_diferencial: Optional[str] = None
    intervention_ed_diferencial_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Psicopedagogía
    intervention_psicopedagogia: Optional[str] = None
    intervention_psicopedagogia_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Fonoaudiología
    intervention_fonoaudiologia: Optional[str] = None
    intervention_fonoaudiologia_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Psicología
    intervention_psicologia: Optional[str] = None
    intervention_psicologia_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Terapia ocupacional
    intervention_terapia_ocupacional: Optional[str] = None
    intervention_terapia_ocupacional_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Kinesiología
    intervention_kinesiologia: Optional[str] = None
    intervention_kinesiologia_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Co-educador sordo
    intervention_coeducador_sordo: Optional[str] = None
    intervention_coeducador_sordo_strategies: Optional[str] = None
    
    # III. Propuesta de intervención - Int. lengua de señas
    intervention_int_lengua_senas: Optional[str] = None
    intervention_int_lengua_senas_strategies: Optional[str] = None
    
    # IV. Seguimiento del PAI
    follow_up_pai: Optional[str] = None
    
    # Profesionales asociados
    professionals: Optional[List[IndividualSupportPlanProfessionalSchema]] = None

class IndividualSupportPlanList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    student_id: Optional[int] = None
    school_id: Optional[int] = None


# Learning objectives catalog (OA Mineduc)

class StoreLearningObjectiveAdmin(BaseModel):
    curriculum_subject_id: int
    education_level_id: int
    code: str
    description: str
    is_priority: bool = False
    sort_order: Optional[int] = None

class UpdateLearningObjectiveAdmin(BaseModel):
    code: Optional[str] = None
    description: Optional[str] = None
    is_priority: Optional[bool] = None
    sort_order: Optional[int] = None
    is_active: Optional[bool] = None


# Document 21 – Individual Curriculum Adaptation Plan (ICAP / PACI)

class IcapAchievementIndicatorSchema(BaseModel):
    id: Optional[str] = None
    text: Optional[str] = None

class IcapLearningObjectiveSchema(BaseModel):
    id: str
    level_code: str
    level_description: str
    is_priority: Optional[bool] = False
    adapted_description: Optional[str] = None
    adapted_level_code: Optional[str] = None
    is_not_adapted: Optional[bool] = False
    oa_not_worked: Optional[bool] = False
    achievement_indicators_enabled: Optional[bool] = False
    achievement_indicators: Optional[List[IcapAchievementIndicatorSchema]] = None

class IcapCurricularAdaptationSubjectSchema(BaseModel):
    subject_id: int
    subject_name: Optional[str] = None
    adaptation_type: Optional[str] = None
    strategies: Optional[str] = None
    learning_objectives: Optional[List[IcapLearningObjectiveSchema]] = None

class IcapProfessionalSchema(BaseModel):
    professional_id: int
    professional_role: Optional[str] = None
    support_roles: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None

class IcapFamilyMemberSchema(BaseModel):
    guardian_id: Optional[int] = None
    name: Optional[str] = None
    identification_number: Optional[str] = None
    family_member_id: Optional[int] = None
    address: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None
    is_emergency_contact: Optional[bool] = False
    is_guardian: Optional[bool] = True

class StoreIndividualCurriculumAdaptationPlan(BaseModel):
    student_id: int
    document_type_id: Optional[int] = 21
    school_id: Optional[int] = None
    semester_id: Optional[int] = None
    report_date: Optional[str] = None
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_born_date: Optional[str] = None
    student_age: Optional[str] = None
    student_nee_id: Optional[int] = None
    student_nee: Optional[str] = None
    student_school: Optional[str] = None
    student_course_id: Optional[int] = None
    student_course: Optional[str] = None
    school_background: Optional[str] = None
    evaluation_background: Optional[str] = None
    nee_diagnosis: Optional[str] = None
    curricular_adaptations: Optional[str] = None
    curricular_adaptation_subjects: Optional[List[IcapCurricularAdaptationSubjectSchema]] = None
    support_resources: Optional[str] = None
    evaluation_criteria: Optional[str] = None
    progress_state: Optional[str] = None
    professionals: Optional[List[IcapProfessionalSchema]] = None
    family_members: Optional[List[IcapFamilyMemberSchema]] = None

class UpdateIndividualCurriculumAdaptationPlan(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = None
    school_id: Optional[int] = None
    semester_id: Optional[int] = None
    report_date: Optional[str] = None
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_born_date: Optional[str] = None
    student_age: Optional[str] = None
    student_nee_id: Optional[int] = None
    student_nee: Optional[str] = None
    student_school: Optional[str] = None
    student_course_id: Optional[int] = None
    student_course: Optional[str] = None
    school_background: Optional[str] = None
    evaluation_background: Optional[str] = None
    nee_diagnosis: Optional[str] = None
    curricular_adaptations: Optional[str] = None
    curricular_adaptation_subjects: Optional[List[IcapCurricularAdaptationSubjectSchema]] = None
    support_resources: Optional[str] = None
    evaluation_criteria: Optional[str] = None
    progress_state: Optional[str] = None
    professionals: Optional[List[IcapProfessionalSchema]] = None
    family_members: Optional[List[IcapFamilyMemberSchema]] = None


# Audit schemas

class StoreAudit(BaseModel):
    user_id: int
    rol_id: Optional[int] = None

class AuditList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    user_id: Optional[int] = None

# PACI / ICAP – PDF estado de avance por asignatura (documento 21)

class PaciProgressOaRowPdf(BaseModel):
    description: Optional[str] = None
    rating: Optional[str] = None
    rating_short: Optional[str] = None

class PaciProgressRowPdf(BaseModel):
    kind: Optional[str] = "oa"
    description: Optional[str] = None
    status: Optional[str] = None
    show_indicators_label: Optional[bool] = False

class PaciProgressStatePdfRequest(BaseModel):
    subject_id: int
    subject_name: Optional[str] = None
    progress_entry_id: Optional[str] = None
    entry_code: Optional[str] = None
    date_from: Optional[str] = None
    date_to: Optional[str] = None
    observations: Optional[str] = None
    responsible_professionals: Optional[str] = None
    signature_name: Optional[str] = None
    signature_role: Optional[str] = None
    signature_rut: Optional[str] = None
    signature_professional_id: Optional[int] = None
    signature_secreduc: Optional[str] = None
    progress_rows: Optional[List[PaciProgressRowPdf]] = None
    student_full_name: Optional[str] = None
    student_rut: Optional[str] = None
    student_born_date: Optional[str] = None
    student_age: Optional[str] = None
    student_nee: Optional[str] = None
    student_school: Optional[str] = None
    student_course: Optional[str] = None

class PaciProgressStateSectionPdf(BaseModel):
    subject_id: int
    subject_name: Optional[str] = None
    progress_entry_id: Optional[str] = None
    entry_code: Optional[str] = None
    date_from: Optional[str] = None
    date_to: Optional[str] = None
    observations: Optional[str] = None
    responsible_professionals: Optional[str] = None
    signature_name: Optional[str] = None
    signature_role: Optional[str] = None
    signature_rut: Optional[str] = None
    signature_professional_id: Optional[int] = None
    signature_secreduc: Optional[str] = None
    progress_rows: Optional[List[PaciProgressRowPdf]] = None
    oa_rows: Optional[List[PaciProgressOaRowPdf]] = None

class PaciIntegralProgressStatePdfRequest(BaseModel):
    student_full_name: Optional[str] = None
    student_rut: Optional[str] = None
    student_born_date: Optional[str] = None
    student_age: Optional[str] = None
    student_nee: Optional[str] = None
    student_school: Optional[str] = None
    student_course: Optional[str] = None
    sections: List[PaciProgressStateSectionPdf]

class PaciFullPdfProfessional(BaseModel):
    name: Optional[str] = None
    professional_role: Optional[str] = None
    support_roles: Optional[str] = None

class PaciFullPdfFamilyMember(BaseModel):
    name: Optional[str] = None
    relationship: Optional[str] = None
    responsibilities: Optional[str] = None

class PaciFullPdfAchievementIndicator(BaseModel):
    text: Optional[str] = None

class PaciFullPdfLearningObjective(BaseModel):
    level_code: Optional[str] = None
    level_description: Optional[str] = None
    is_priority: Optional[bool] = False
    adapted_description: Optional[str] = None
    adapted_level_code: Optional[str] = None
    is_not_adapted: Optional[bool] = False
    oa_not_worked: Optional[bool] = False
    achievement_indicators_enabled: Optional[bool] = False
    achievement_indicators: Optional[List[PaciFullPdfAchievementIndicator]] = None

class PaciFullPdfCurricularSubject(BaseModel):
    subject_name: Optional[str] = None
    adaptation_type: Optional[str] = None
    strategies: Optional[str] = None
    learning_objectives: Optional[List[PaciFullPdfLearningObjective]] = None

class PaciFullPdfProgressEntry(BaseModel):
    subject_name: Optional[str] = None
    entry_code: Optional[str] = None
    date_from: Optional[str] = None
    date_to: Optional[str] = None
    responsible_professionals: Optional[str] = None
    observations: Optional[str] = None
    progress_rows: Optional[List[PaciProgressRowPdf]] = None

class PaciFullPdfRequest(BaseModel):
    paci_full: bool = True
    student_full_name: Optional[str] = None
    student_rut: Optional[str] = None
    student_born_date: Optional[str] = None
    student_age: Optional[str] = None
    student_nee: Optional[str] = None
    student_school: Optional[str] = None
    student_course: Optional[str] = None
    report_date: Optional[str] = None
    school_background: Optional[str] = None
    evaluation_background: Optional[str] = None
    human_resources: Optional[str] = None
    material_resources: Optional[str] = None
    evaluation_adaptation_criteria: Optional[str] = None
    learning_results_evaluation: Optional[str] = None
    evaluation_promotion_criteria: Optional[str] = None
    professionals: Optional[List[PaciFullPdfProfessional]] = None
    family_members: Optional[List[PaciFullPdfFamilyMember]] = None
    curricular_subjects: Optional[List[PaciFullPdfCurricularSubject]] = None
    progress_entries: Optional[List[PaciFullPdfProgressEntry]] = None


# Progress Status Individual Support schemas (Estado de avance PAI - Documento 19)

class PaiObjectiveSchema(BaseModel):
    id: Optional[int] = None
    number: Optional[int] = None
    description: Optional[str] = None
    progress_level: Optional[str] = None

class StoreProgressStatusIndividualSupport(BaseModel):
    student_id: Optional[int] = None
    school_id: Optional[int] = None
    document_type_id: Optional[int] = 19  # Siempre 19 para progress status individual support
    
    # I. Identificación del/la estudiante
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_born_date: Optional[str] = None  # Formato: "YYYY-MM-DD"
    student_age: Optional[str] = None
    student_nee_id: Optional[int] = None
    student_school: Optional[str] = None
    student_course_id: Optional[int] = None
    
    # Fecha y periodo
    progress_date: Optional[str] = None  # Formato: "YYYY-MM-DD"
    period_id: Optional[int] = None  # 1=1er Trimestre, 2=2do Trimestre, 3=1er Semestre, 4=2do Semestre
    
    # Apoderado/a
    guardian_relationship_id: Optional[int] = None
    guardian_name: Optional[str] = None
    
    # Profesionales responsables
    responsible_professionals: Optional[str] = None  # IDs de profesionales separados por comas: "1,2,3"
    
    # PAI seleccionado y objetivos
    selected_pai_id: Optional[int] = None
    pai_objectives: Optional[List[PaiObjectiveSchema]] = None
    pai_observations: Optional[str] = None

    # Sugerencias
    suggestions_family: Optional[str] = None
    suggestions_establishment: Optional[str] = None

class UpdateProgressStatusIndividualSupport(BaseModel):
    student_id: Optional[int] = None
    school_id: Optional[int] = None
    document_type_id: Optional[int] = None
    
    # I. Identificación del/la estudiante
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_born_date: Optional[str] = None
    student_age: Optional[str] = None
    student_nee_id: Optional[int] = None
    student_school: Optional[str] = None
    student_course_id: Optional[int] = None
    
    # Fecha y periodo
    progress_date: Optional[str] = None
    period_id: Optional[int] = None
    
    # Apoderado/a
    guardian_relationship_id: Optional[int] = None
    guardian_name: Optional[str] = None
    
    # Profesionales responsables
    responsible_professionals: Optional[str] = None
    
    # PAI seleccionado y objetivos
    selected_pai_id: Optional[int] = None
    pai_objectives: Optional[List[PaiObjectiveSchema]] = None
    pai_observations: Optional[str] = None

    # Sugerencias
    suggestions_family: Optional[str] = None
    suggestions_establishment: Optional[str] = None

class ProgressStatusIndividualSupportList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    student_id: Optional[int] = None
    school_id: Optional[int] = None

# Fonoaudiological Report schemas (Informe fonoaudiológico - Documento 8)

class StoreFonoaudiologicalReport(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = 8
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_born_date: Optional[str] = None  # "YYYY-MM-DD"
    establishment_id: Optional[str] = None
    course_id: Optional[int] = None
    responsible_professionals: Optional[List[int]] = None  # JSON: IDs de profesionales
    report_date: Optional[str] = None  # "YYYY-MM-DD"
    type_id: Optional[int] = None  # 1=Ingreso, 2=Reevaluación
    reason_evaluation: Optional[str] = None
    evaluation_instruments: Optional[str] = None
    relevant_background: Optional[str] = None
    behaviors_observed: Optional[str] = None
    orofacial_auditory: Optional[str] = None
    phonological_level: Optional[str] = None
    morphosyntactic_level: Optional[str] = None
    semantic_level: Optional[str] = None
    pragmatic_level: Optional[str] = None
    additional_observations: Optional[str] = None
    diagnostic_synthesis: Optional[str] = None
    suggestions_family: Optional[str] = None
    suggestions_establishment: Optional[str] = None

class UpdateFonoaudiologicalReport(BaseModel):
    student_id: Optional[int] = None
    document_type_id: Optional[int] = None
    student_full_name: Optional[str] = None
    student_identification_number: Optional[str] = None
    student_born_date: Optional[str] = None
    establishment_id: Optional[str] = None
    course_id: Optional[int] = None
    responsible_professionals: Optional[List[int]] = None
    report_date: Optional[str] = None
    type_id: Optional[int] = None
    reason_evaluation: Optional[str] = None
    evaluation_instruments: Optional[str] = None
    relevant_background: Optional[str] = None
    behaviors_observed: Optional[str] = None
    orofacial_auditory: Optional[str] = None
    phonological_level: Optional[str] = None
    morphosyntactic_level: Optional[str] = None
    semantic_level: Optional[str] = None
    pragmatic_level: Optional[str] = None
    additional_observations: Optional[str] = None
    diagnostic_synthesis: Optional[str] = None
    suggestions_family: Optional[str] = None
    suggestions_establishment: Optional[str] = None

class StoreFurForm(BaseModel):
    """Document 6 – Formulario de revaluación (FUR). Acepta todos los campos del formulario."""
    student_id: int
    school_id: Optional[int] = None
    student_identification_number: Optional[str] = None
    document_type_id: Optional[int] = 6
    fur_variant: Optional[str] = "dea"

    class Config:
        extra = "allow"

class StoreIdtelReport(BaseModel):
    """Document 9 – Informe fonoaudiológico IDTEL. Acepta todos los campos del formulario."""
    student_id: int
    document_type_id: Optional[int] = 9
    quantitative_locked: Optional[bool] = None

    class Config:
        extra = "allow"

class StorePsychomotorEvaluationReport(BaseModel):
    """Informe de evaluación psicomotriz. Acepta todos los campos del formulario (JSON en BD)."""
    student_id: int
    document_type_id: Optional[int] = None

    class Config:
        extra = "allow"


# Document 31 – Pauta de evaluación pedagógica - Docente de aula - first grade

class FonoaudiologicalReportList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    student_id: Optional[int] = None

# School Integration Program Exit Certificate

class StoreSchoolIntegrationProgramExitCertificate(BaseModel):
    student_id: Optional[int] = None
    professional_id: Optional[int] = None
    document_description: Optional[str] = None
    professional_certification_number: Optional[str] = None
    professional_career: Optional[str] = None
    guardian_id: Optional[int] = None

class UpdateSchoolIntegrationProgramExitCertificate(BaseModel):
    student_id: Optional[int] = None
    professional_id: Optional[int] = None
    document_description: Optional[str] = None
    professional_certification_number: Optional[str] = None
    professional_career: Optional[str] = None
    guardian_id: Optional[int] = None

class SchoolIntegrationProgramExitCertificateList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    student_id: Optional[int] = None


# Anamnesis (documento tipo 3)

class AnamnesisInformantSchema(BaseModel):
    id: Optional[int] = None
    sort_order: Optional[int] = 0
    name: Optional[str] = None
    relationship: Optional[str] = None
    presence: Optional[str] = None
    interview_date: Optional[date] = None

    @validator("interview_date", pre=True)
    def interview_date_empty_to_none(cls, v):
        return _empty_str_to_none(v)

class AnamnesisInterviewerSchema(BaseModel):
    id: Optional[int] = None
    sort_order: Optional[int] = 0
    professional_id: Optional[int] = None
    role: Optional[str] = None
    interview_date: Optional[date] = None

    @validator("interview_date", pre=True)
    def interview_date_empty_to_none(cls, v):
        return _empty_str_to_none(v)

class AnamnesisHouseholdMemberSchema(BaseModel):
    id: Optional[int] = None
    sort_order: Optional[int] = 0
    name: Optional[str] = None
    relationship: Optional[str] = None
    age: Optional[str] = None
    schooling: Optional[str] = None
    occupation: Optional[str] = None

class StoreAnamnesis(BaseModel):
    student_id: int
    version: Optional[int] = 1
    student_full_name: Optional[str] = None
    gender_id: Optional[int] = None
    born_date: Optional[date] = None
    age: Optional[str] = None
    nationality_id: Optional[int] = None
    address: Optional[str] = None
    phone: Optional[str] = None
    native_language: Optional[str] = None
    native_language_domain: Optional[Union[List, Dict]] = None
    language_used: Optional[str] = None
    language_used_domain: Optional[Union[List, Dict]] = None
    current_schooling: Optional[str] = None
    school_name: Optional[str] = None
    interview_reason: Optional[str] = None
    diagnosis_has: Optional[int] = None
    diagnosis_detail: Optional[str] = None
    specialists: Optional[Union[List, Dict]] = None
    first_year_notes: Optional[str] = None
    birth_type_id: Optional[int] = None
    birth_reason: Optional[str] = None
    birth_medical_assistance: Optional[int] = None
    birth_weight: Optional[str] = None
    birth_height: Optional[str] = None
    first_year_conditions: Optional[Union[List, Dict]] = None
    first_year_conditions_other_specify: Optional[str] = None
    first_year_periodic_health_checkups: Optional[int] = None
    first_year_vaccines: Optional[int] = None
    first_year_observations: Optional[str] = None
    sm_head_control: Optional[str] = None
    sm_sits_alone: Optional[str] = None
    sm_walks_without_support: Optional[str] = None
    sm_first_words: Optional[str] = None
    sm_first_phrases: Optional[str] = None
    sm_dresses_alone: Optional[str] = None
    sm_bladder_day: Optional[str] = None
    sm_bladder_night: Optional[str] = None
    sm_bowel_day: Optional[str] = None
    sm_bowel_night: Optional[str] = None
    sm_observations_1: Optional[str] = None
    sm_motor_activity: Optional[str] = None
    sm_muscle_tone: Optional[str] = None
    sm_walking_stability: Optional[int] = None
    sm_frequent_falls: Optional[int] = None
    sm_lateral_dominance: Optional[str] = None
    sm_fine_grab: Optional[int] = None
    sm_fine_grip: Optional[int] = None
    sm_fine_pinch: Optional[int] = None
    sm_fine_draw: Optional[int] = None
    sm_fine_write: Optional[int] = None
    sm_fine_thread: Optional[int] = None
    sm_cog_reacts_familiar: Optional[int] = None
    sm_cog_demands_company: Optional[int] = None
    sm_cog_smiles_babbles: Optional[int] = None
    sm_cog_manipulates_explores: Optional[int] = None
    sm_cog_understands_prohibitions: Optional[int] = None
    sm_cog_poor_eye_hand: Optional[int] = None
    sm_observations_2: Optional[str] = None
    vision_interested_stimuli: Optional[int] = None
    vision_irritated_eyes: Optional[int] = None
    vision_headaches: Optional[int] = None
    vision_squints: Optional[int] = None
    vision_follows_movement: Optional[int] = None
    vision_abnormal_movements: Optional[int] = None
    vision_erroneous_behaviors: Optional[int] = None
    vision_diagnosis: Optional[int] = None
    hearing_interested_stimuli: Optional[int] = None
    hearing_recognizes_voices: Optional[int] = None
    hearing_turns_head: Optional[int] = None
    hearing_ears_to_tv: Optional[int] = None
    hearing_covers_ears: Optional[int] = None
    hearing_earaches: Optional[int] = None
    hearing_pronunciation_adequate: Optional[int] = None
    hearing_diagnosis: Optional[int] = None
    vision_hearing_observations: Optional[str] = None
    language_communication_method: Optional[str] = None
    language_communication_other: Optional[str] = None
    language_exp_babbles: Optional[int] = None
    language_exp_vocalizes_gestures: Optional[int] = None
    language_exp_emits_words: Optional[int] = None
    language_exp_emits_phrases: Optional[int] = None
    language_exp_relates_experiences: Optional[int] = None
    language_exp_clear_pronunciation: Optional[int] = None
    language_comp_identifies_objects: Optional[int] = None
    language_comp_identifies_people: Optional[int] = None
    language_comp_understands_abstract: Optional[int] = None
    language_comp_responds_coherently: Optional[int] = None
    language_comp_follows_simple_instructions: Optional[int] = None
    language_comp_follows_complex_instructions: Optional[int] = None
    language_comp_follows_group_instructions: Optional[int] = None
    language_comp_understands_stories: Optional[int] = None
    language_oral_loss: Optional[str] = None
    language_observations: Optional[str] = None
    social_relates_spontaneously: Optional[int] = None
    social_explains_behaviors: Optional[int] = None
    social_participates_groups: Optional[int] = None
    social_prefers_individual: Optional[int] = None
    social_echolalic_language: Optional[int] = None
    social_difficulty_adapting: Optional[int] = None
    social_relates_collaboratively: Optional[int] = None
    social_respects_social_norms: Optional[int] = None
    social_respects_school_norms: Optional[int] = None
    social_shows_humor: Optional[int] = None
    social_stereotyped_movements: Optional[int] = None
    social_frequent_tantrums: Optional[int] = None
    social_reaction_lights: Optional[str] = None
    social_reaction_sounds: Optional[str] = None
    social_reaction_strange_people: Optional[str] = None
    social_observations: Optional[str] = None
    health_vaccines_up_to_date: Optional[int] = None
    health_epilepsy: Optional[int] = None
    health_heart_problems: Optional[int] = None
    health_paraplegia: Optional[int] = None
    health_hearing_loss: Optional[int] = None
    health_vision_loss: Optional[int] = None
    health_motor_disorder: Optional[int] = None
    health_bronchorespiratory: Optional[int] = None
    health_infectious_disease: Optional[int] = None
    health_emotional_disorder: Optional[int] = None
    health_behavioral_disorder: Optional[int] = None
    health_other: Optional[int] = None
    health_other_specify: Optional[str] = None
    health_problems_treatment: Optional[str] = None
    health_diet: Optional[str] = None
    health_diet_other: Optional[str] = None
    health_weight: Optional[str] = None
    health_sleep_pattern: Optional[str] = None
    health_sleep_insomnia: Optional[int] = 0
    health_sleep_nightmares: Optional[int] = 0
    health_sleep_terrors: Optional[int] = 0
    health_sleep_sleepwalking: Optional[int] = 0
    health_sleep_good_mood: Optional[int] = 0
    health_sleep_hours: Optional[str] = None
    health_sleeps_alone: Optional[str] = None
    health_sleeps_specify: Optional[str] = None
    health_mood_behavior: Optional[str] = None
    health_mood_other: Optional[str] = None
    health_current_observations: Optional[str] = None
    family_health_history: Optional[str] = None
    family_health_observations: Optional[str] = None
    school_entry_age: Optional[str] = None
    attended_kindergarten: Optional[int] = None
    schools_count: Optional[str] = None
    teaching_modality: Optional[str] = None
    changes_reason: Optional[str] = None
    repeated_grade: Optional[int] = None
    repeated_courses: Optional[str] = None
    repeated_reason: Optional[str] = None
    current_level: Optional[str] = None
    learning_difficulty: Optional[int] = None
    participation_difficulty: Optional[int] = None
    disruptive_behavior: Optional[int] = None
    attends_regularly: Optional[int] = None
    attends_gladly: Optional[int] = None
    family_support_homework: Optional[int] = None
    friends: Optional[int] = None
    family_attitude: Optional[str] = None
    performance_assessment: Optional[str] = None
    performance_reasons: Optional[str] = None
    response_difficulties: Optional[Union[List, Dict]] = None
    response_difficulties_other: Optional[str] = None
    response_success: Optional[Union[List, Dict]] = None
    response_success_other: Optional[str] = None
    rewards: Optional[Union[List, Dict]] = None
    rewards_other: Optional[str] = None
    supporters: Optional[Union[List, Dict]] = None
    supporters_other_professionals: Optional[str] = None
    expectations: Optional[str] = None
    environment: Optional[str] = None
    final_comments: Optional[str] = None
    informants: Optional[List[AnamnesisInformantSchema]] = None
    interviewers: Optional[List[AnamnesisInterviewerSchema]] = None
    household_members: Optional[List[AnamnesisHouseholdMemberSchema]] = None

class UpdateAnamnesis(BaseModel):
    student_id: Optional[int] = None
    version: Optional[int] = None
    student_full_name: Optional[str] = None
    gender_id: Optional[int] = None
    born_date: Optional[date] = None
    age: Optional[str] = None
    nationality_id: Optional[int] = None
    address: Optional[str] = None
    phone: Optional[str] = None
    native_language: Optional[str] = None
    native_language_domain: Optional[Union[List, Dict]] = None
    language_used: Optional[str] = None
    language_used_domain: Optional[Union[List, Dict]] = None
    current_schooling: Optional[str] = None
    school_name: Optional[str] = None
    interview_reason: Optional[str] = None
    diagnosis_has: Optional[int] = None
    diagnosis_detail: Optional[str] = None
    specialists: Optional[Union[List, Dict]] = None
    first_year_notes: Optional[str] = None
    birth_type_id: Optional[int] = None
    birth_reason: Optional[str] = None
    birth_medical_assistance: Optional[int] = None
    birth_weight: Optional[str] = None
    birth_height: Optional[str] = None
    first_year_conditions: Optional[Union[List, Dict]] = None
    first_year_conditions_other_specify: Optional[str] = None
    first_year_periodic_health_checkups: Optional[int] = None
    first_year_vaccines: Optional[int] = None
    first_year_observations: Optional[str] = None
    sm_head_control: Optional[str] = None
    sm_sits_alone: Optional[str] = None
    sm_walks_without_support: Optional[str] = None
    sm_first_words: Optional[str] = None
    sm_first_phrases: Optional[str] = None
    sm_dresses_alone: Optional[str] = None
    sm_bladder_day: Optional[str] = None
    sm_bladder_night: Optional[str] = None
    sm_bowel_day: Optional[str] = None
    sm_bowel_night: Optional[str] = None
    sm_observations_1: Optional[str] = None
    sm_motor_activity: Optional[str] = None
    sm_muscle_tone: Optional[str] = None
    sm_walking_stability: Optional[int] = None
    sm_frequent_falls: Optional[int] = None
    sm_lateral_dominance: Optional[str] = None
    sm_fine_grab: Optional[int] = None
    sm_fine_grip: Optional[int] = None
    sm_fine_pinch: Optional[int] = None
    sm_fine_draw: Optional[int] = None
    sm_fine_write: Optional[int] = None
    sm_fine_thread: Optional[int] = None
    sm_cog_reacts_familiar: Optional[int] = None
    sm_cog_demands_company: Optional[int] = None
    sm_cog_smiles_babbles: Optional[int] = None
    sm_cog_manipulates_explores: Optional[int] = None
    sm_cog_understands_prohibitions: Optional[int] = None
    sm_cog_poor_eye_hand: Optional[int] = None
    sm_observations_2: Optional[str] = None
    vision_interested_stimuli: Optional[int] = None
    vision_irritated_eyes: Optional[int] = None
    vision_headaches: Optional[int] = None
    vision_squints: Optional[int] = None
    vision_follows_movement: Optional[int] = None
    vision_abnormal_movements: Optional[int] = None
    vision_erroneous_behaviors: Optional[int] = None
    vision_diagnosis: Optional[int] = None
    hearing_interested_stimuli: Optional[int] = None
    hearing_recognizes_voices: Optional[int] = None
    hearing_turns_head: Optional[int] = None
    hearing_ears_to_tv: Optional[int] = None
    hearing_covers_ears: Optional[int] = None
    hearing_earaches: Optional[int] = None
    hearing_pronunciation_adequate: Optional[int] = None
    hearing_diagnosis: Optional[int] = None
    vision_hearing_observations: Optional[str] = None
    language_communication_method: Optional[str] = None
    language_communication_other: Optional[str] = None
    language_exp_babbles: Optional[int] = None
    language_exp_vocalizes_gestures: Optional[int] = None
    language_exp_emits_words: Optional[int] = None
    language_exp_emits_phrases: Optional[int] = None
    language_exp_relates_experiences: Optional[int] = None
    language_exp_clear_pronunciation: Optional[int] = None
    language_comp_identifies_objects: Optional[int] = None
    language_comp_identifies_people: Optional[int] = None
    language_comp_understands_abstract: Optional[int] = None
    language_comp_responds_coherently: Optional[int] = None
    language_comp_follows_simple_instructions: Optional[int] = None
    language_comp_follows_complex_instructions: Optional[int] = None
    language_comp_follows_group_instructions: Optional[int] = None
    language_comp_understands_stories: Optional[int] = None
    language_oral_loss: Optional[str] = None
    language_observations: Optional[str] = None
    social_relates_spontaneously: Optional[int] = None
    social_explains_behaviors: Optional[int] = None
    social_participates_groups: Optional[int] = None
    social_prefers_individual: Optional[int] = None
    social_echolalic_language: Optional[int] = None
    social_difficulty_adapting: Optional[int] = None
    social_relates_collaboratively: Optional[int] = None
    social_respects_social_norms: Optional[int] = None
    social_respects_school_norms: Optional[int] = None
    social_shows_humor: Optional[int] = None
    social_stereotyped_movements: Optional[int] = None
    social_frequent_tantrums: Optional[int] = None
    social_reaction_lights: Optional[str] = None
    social_reaction_sounds: Optional[str] = None
    social_reaction_strange_people: Optional[str] = None
    social_observations: Optional[str] = None
    health_vaccines_up_to_date: Optional[int] = None
    health_epilepsy: Optional[int] = None
    health_heart_problems: Optional[int] = None
    health_paraplegia: Optional[int] = None
    health_hearing_loss: Optional[int] = None
    health_vision_loss: Optional[int] = None
    health_motor_disorder: Optional[int] = None
    health_bronchorespiratory: Optional[int] = None
    health_infectious_disease: Optional[int] = None
    health_emotional_disorder: Optional[int] = None
    health_behavioral_disorder: Optional[int] = None
    health_other: Optional[int] = None
    health_other_specify: Optional[str] = None
    health_problems_treatment: Optional[str] = None
    health_diet: Optional[str] = None
    health_diet_other: Optional[str] = None
    health_weight: Optional[str] = None
    health_sleep_pattern: Optional[str] = None
    health_sleep_insomnia: Optional[int] = None
    health_sleep_nightmares: Optional[int] = None
    health_sleep_terrors: Optional[int] = None
    health_sleep_sleepwalking: Optional[int] = None
    health_sleep_good_mood: Optional[int] = None
    health_sleep_hours: Optional[str] = None
    health_sleeps_alone: Optional[str] = None
    health_sleeps_specify: Optional[str] = None
    health_mood_behavior: Optional[str] = None
    health_mood_other: Optional[str] = None
    health_current_observations: Optional[str] = None
    family_health_history: Optional[str] = None
    family_health_observations: Optional[str] = None
    school_entry_age: Optional[str] = None
    attended_kindergarten: Optional[int] = None
    schools_count: Optional[str] = None
    teaching_modality: Optional[str] = None
    changes_reason: Optional[str] = None
    repeated_grade: Optional[int] = None
    repeated_courses: Optional[str] = None
    repeated_reason: Optional[str] = None
    current_level: Optional[str] = None
    learning_difficulty: Optional[int] = None
    participation_difficulty: Optional[int] = None
    disruptive_behavior: Optional[int] = None
    attends_regularly: Optional[int] = None
    attends_gladly: Optional[int] = None
    family_support_homework: Optional[int] = None
    friends: Optional[int] = None
    family_attitude: Optional[str] = None
    performance_assessment: Optional[str] = None
    performance_reasons: Optional[str] = None
    response_difficulties: Optional[Union[List, Dict]] = None
    response_difficulties_other: Optional[str] = None
    response_success: Optional[Union[List, Dict]] = None
    response_success_other: Optional[str] = None
    rewards: Optional[Union[List, Dict]] = None
    rewards_other: Optional[str] = None
    supporters: Optional[Union[List, Dict]] = None
    supporters_other_professionals: Optional[str] = None
    expectations: Optional[str] = None
    environment: Optional[str] = None
    final_comments: Optional[str] = None
    informants: Optional[List[AnamnesisInformantSchema]] = None
    interviewers: Optional[List[AnamnesisInterviewerSchema]] = None
    household_members: Optional[List[AnamnesisHouseholdMemberSchema]] = None

class AnamnesisList(BaseModel):
    page: Optional[int] = None
    per_page: int = 10
    student_id: Optional[int] = None

