from __future__ import annotations

from datetime import date, datetime

from pydantic import BaseModel, ConfigDict, Field


class DataCountItem(BaseModel):
    code: str
    label: str
    count: int


class BroadcastMessageCreate(BaseModel):
    title: str = Field(min_length=1, max_length=100)
    content: str = Field(min_length=1, max_length=500)
    attendance_point_names: list[str] = Field(default_factory=list)
    tone: str = "INFO"
    status: str = "ACTIVE"
    starts_at: datetime | None = None
    ends_at: datetime | None = None
    sort_no: int = 0


class BroadcastMessageRead(BroadcastMessageCreate):
    broadcast_id: int
    created_by: int | str | None = None
    created_at: datetime
    updated_at: datetime


class AiAssistantConfigUpdate(BaseModel):
    assistant_name: str = Field(default="嘉恒工艺助手", min_length=1, max_length=100)
    provider_name: str | None = None
    api_base_url: str | None = None
    api_key: str | None = None
    model_name: str | None = None
    temperature: float = Field(default=0.3, ge=0, le=2)
    system_prompt: str | None = None
    enabled: bool = False


class AiAssistantConfigRead(AiAssistantConfigUpdate):
    config_id: int | None = None
    api_key_configured: bool = False
    updated_at: datetime | None = None


class SystemConfigUpdate(BaseModel):
    config_value: str = Field(min_length=1, max_length=500)
    remark: str | None = Field(default=None, max_length=500)


class SystemConfigRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    config_code: str
    config_name: str
    config_value: str
    remark: str | None = None
    updated_at: datetime | None = None


class SmartOperationReportConfigUpdate(BaseModel):
    enabled: bool
    remark: str | None = Field(default=None, max_length=500)


class SmartOperationReportConfigRead(BaseModel):
    config_code: str = "SMART_OPERATION_REPORT_ENABLED"
    config_name: str = "对接智能报工小程序"
    enabled: bool = True
    config_value: str = "开启"
    remark: str | None = None
    updated_at: datetime | None = None


class LoginUser(BaseModel):
    user_id: int
    username: str
    employee_id: int
    mobile: str | None = None
    display_name: str
    title: str
    dept_name: str | None = None
    role_codes: list[str]
    role_names: list[str]
    permission_codes: list[str]


class AuthLoginRequest(BaseModel):
    username: str
    password: str


class AuthChangePasswordRequest(BaseModel):
    old_password: str = Field(min_length=1)
    new_password: str = Field(min_length=6, max_length=128)


class AuthResetPasswordRequest(BaseModel):
    username: str = Field(min_length=1, max_length=50)
    new_password: str = Field(min_length=6, max_length=128)


class AuthSession(LoginUser):
    access_token: str
    token_type: str
    expires_at: datetime


class DepartmentRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    dept_code: str
    dept_name: str
    dept_type: str
    manager_name: str | None = None
    status: str


class EmployeeRead(BaseModel):
    id: int
    employee_code: str
    employee_name: str
    dept_id: int
    dept_name: str | None = None
    mobile: str | None = None
    gender: str | None = None
    hire_date: date | None = None
    job_title: str | None = None
    shift_code: str | None = None
    is_operator: bool
    is_workshop_staff: bool
    status: str
    remark: str | None = None
    username: str | None = None
    role_names: list[str] = Field(default_factory=list)


class EmployeeCreate(BaseModel):
    employee_name: str
    dept_id: int = Field(gt=0)
    mobile: str | None = None
    gender: str | None = None
    hire_date: date | None = None
    job_title: str | None = None
    shift_code: str | None = None
    manager_employee_id: int | None = None
    is_operator: bool = False
    is_workshop_staff: bool = False
    status: str = "ACTIVE"
    remark: str | None = None


class EmployeeUpdate(BaseModel):
    employee_name: str
    dept_id: int = Field(gt=0)
    mobile: str | None = None
    gender: str | None = None
    hire_date: date | None = None
    job_title: str | None = None
    shift_code: str | None = None
    manager_employee_id: int | None = None
    is_operator: bool = False
    is_workshop_staff: bool = False
    status: str = "ACTIVE"
    remark: str | None = None


class MiniAppPersonnelRead(BaseModel):
    phone: str
    name: str
    role: str | None = None
    role_name: str | None = None
    roles: list[str] = Field(default_factory=list)
    role_names: list[str] = Field(default_factory=list)
    attendance_point_names: list[str] = Field(default_factory=list)
    is_temporary: bool = False
    temporary_expires_at: datetime | None = None
    temporary_expired: bool = False
    created_at: datetime | None = None
    updated_at: datetime | None = None


class MiniAppPersonnelUpsert(BaseModel):
    phone: str = Field(min_length=1, max_length=20)
    name: str = Field(min_length=1, max_length=64)
    roles: list[str] = Field(default_factory=lambda: ["worker"])
    attendance_point_names: list[str] = Field(default_factory=list)
    is_temporary: bool = False
    temporary_expires_at: datetime | None = None


class MiniAppAttendancePointRead(BaseModel):
    name: str
    latitude: float | None = None
    longitude: float | None = None
    radius_meters: int = 500
    remark: str | None = None
    is_active: bool = True
    created_at: datetime | None = None
    updated_at: datetime | None = None


class MiniAppProductRead(BaseModel):
    attendance_point_name: str
    project_no: str
    product_name: str
    profile_no: str | None = None
    material_code: str | None = None
    material_name: str | None = None
    supplier: str | None = None
    product_net_weight_kg: float | None = None
    product_gross_weight_kg: float | None = None
    allowed_scrap_rate: float | None = None
    scrap_loss_rate: float | None = None
    waste_price_yuan_per_kg: float | None = None
    device_no: str
    process_name: str | None = None
    stamping_method: str | None = None
    operator_count: float = 1
    standard_beat: float = 0
    standard_workload: float = 0
    display_name: str
    created_at: datetime | None = None
    updated_at: datetime | None = None


class MiniAppProductUpsert(BaseModel):
    attendance_point_name: str = Field(min_length=1, max_length=128)
    project_no: str = Field(min_length=1, max_length=64)
    product_name: str = Field(min_length=1, max_length=255)
    profile_no: str | None = None
    material_code: str | None = None
    material_name: str | None = None
    supplier: str | None = None
    product_net_weight_kg: float | None = Field(default=None, ge=0)
    product_gross_weight_kg: float | None = Field(default=None, ge=0)
    allowed_scrap_rate: float | None = Field(default=None, ge=0)
    scrap_loss_rate: float | None = Field(default=None, ge=0)
    waste_price_yuan_per_kg: float | None = Field(default=None, ge=0)
    device_no: str = Field(default="", max_length=64)
    process_name: str = Field(default="", max_length=128)
    stamping_method: str | None = None
    operator_count: float = Field(default=1, ge=0)
    standard_beat: float = Field(default=0, ge=0)
    standard_workload: float = Field(default=0, ge=0)
    original_attendance_point_name: str | None = None
    original_project_no: str | None = None
    original_product_name: str | None = None
    original_device_no: str | None = None
    original_process_name: str | None = None


class MiniAppProductImportResult(BaseModel):
    imported: int = 0
    updated: int = 0
    skipped: int = 0
    errors: list[str] = Field(default_factory=list)
    material_sync: dict[str, object] = Field(default_factory=dict)
    product_specs: dict[str, int] = Field(default_factory=dict)
    message: str


class MiniAppMaterialWastePriceSync(BaseModel):
    material_code: str | None = None
    material_name: str | None = None
    waste_price_yuan_per_kg: float = Field(default=0, ge=0)


class WarehouseRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    warehouse_code: str
    warehouse_name: str
    warehouse_type: str
    status: str


class ItemRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    item_code: str
    item_name: str
    item_type: str
    specification: str | None = None
    material_grade: str | None = None
    unit_weight_kg: float
    safety_stock_weight_kg: float
    status: str


class MaterialRead(BaseModel):
    item_id: int
    item_code: str
    item_name: str
    specification: str | None = None
    material_grade: str | None = None
    unit_weight_kg: float = 0
    safety_stock_weight_kg: float = 0
    scrap_sale_price: float = 0
    default_supplier_id: int | None = None
    supplier_name: str | None = None
    purchase_calc_mode: str
    min_purchase_qty: float
    purchase_multiple_qty: float
    purchase_multiple_weight_kg: float
    lead_time_days: int
    quality_rule: str | None = None
    remark: str | None = None
    status: str = "ACTIVE"


class ProductRead(BaseModel):
    item_id: int
    item_code: str
    item_name: str
    specification: str | None = None
    drawing_no: str | None = None
    product_family: str | None = None
    version_no: str
    unit_weight_kg: float
    allowed_scrap_rate: float
    standard_output_qty: float = 0
    quality_standard: str | None = None
    safety_stock_weight_kg: float = 0
    status: str


class ProductCreate(BaseModel):
    item_code: str | None = None
    item_name: str
    specification: str | None = None
    drawing_no: str | None = None
    product_family: str | None = None
    version_no: str = "V1.0"
    unit_weight_kg: float = Field(gt=0)
    allowed_scrap_rate: float = Field(default=0, ge=0)
    standard_output_qty: float = Field(default=0, ge=0)
    quality_standard: str | None = None
    safety_stock_weight_kg: float = Field(default=0, ge=0)
    status: str = "ACTIVE"


class ProductUpdate(BaseModel):
    item_code: str | None = None
    item_name: str
    specification: str | None = None
    drawing_no: str | None = None
    product_family: str | None = None
    version_no: str
    unit_weight_kg: float = Field(gt=0)
    allowed_scrap_rate: float = Field(default=0, ge=0)
    standard_output_qty: float = Field(default=0, ge=0)
    quality_standard: str | None = None
    safety_stock_weight_kg: float = Field(default=0, ge=0)
    status: str = "ACTIVE"


class MaterialCreate(BaseModel):
    item_code: str | None = None
    item_name: str
    specification: str
    material_grade: str
    unit_weight_kg: float = Field(gt=0)
    safety_stock_weight_kg: float = Field(default=0, ge=0)
    scrap_sale_price: float = Field(default=0, ge=0)
    default_supplier_id: int | None = None
    purchase_calc_mode: str = "BY_WEIGHT"
    min_purchase_qty: float = Field(default=0, ge=0)
    purchase_multiple_qty: float = Field(default=0, ge=0)
    purchase_multiple_weight_kg: float = Field(default=0, ge=0)
    lead_time_days: int = Field(default=0, ge=0)
    quality_rule: str | None = None
    remark: str | None = None
    status: str = "ACTIVE"


class MaterialUpdate(MaterialCreate):
    pass


class BomItemPayload(BaseModel):
    seq_no: int = Field(gt=0)
    material_item_id: int = Field(gt=0)
    usage_type: str = "WEIGHT"
    qty_per_piece: float = Field(default=1, gt=0)
    net_weight_per_piece_kg: float = Field(default=0, ge=0)
    gross_weight_per_piece_kg: float = Field(default=0, ge=0)
    loss_rate: float = Field(default=0, ge=0)
    issue_over_tolerance_rate: float = Field(default=0, ge=0)
    remark: str | None = None


class BomItemRead(BomItemPayload):
    bom_item_id: int
    material_code: str
    material_name: str
    seq_no: int
    material_item_id: int
    usage_type: str
    qty_per_piece: float
    net_weight_per_piece_kg: float
    gross_weight_per_piece_kg: float
    loss_rate: float
    issue_over_tolerance_rate: float
    remark: str | None = None


class BomRead(BaseModel):
    bom_id: int
    bom_code: str
    product_item_id: int
    product_code: str
    product_name: str
    version_no: str
    is_default: bool
    status: str
    effective_date: date | None = None
    expire_date: date | None = None
    remark: str | None = None
    item_count: int = 0
    items: list[BomItemRead] = Field(default_factory=list)


class BomUpsert(BaseModel):
    bom_code: str | None = None
    product_item_id: int
    version_no: str = "V1.0"
    is_default: bool = True
    status: str = "ACTIVE"
    effective_date: date | None = None
    expire_date: date | None = None
    remark: str | None = None
    items: list[BomItemPayload]


class ProcessRead(BaseModel):
    process_id: int
    process_code: str
    process_name: str
    process_type: str
    is_report_required: bool
    is_quality_gate: bool
    status: str


class RouteOperationPayload(BaseModel):
    seq_no: int = Field(gt=0)
    process_id: int = Field(gt=0)
    work_center_id: int = Field(gt=0)
    operation_name: str
    std_setup_minutes: float = Field(default=0, ge=0)
    std_cycle_seconds: float = Field(default=0, ge=0)
    std_labor_cost: float = Field(default=0, ge=0)
    std_machine_cost: float = Field(default=0, ge=0)
    std_outsource_cost: float = Field(default=0, ge=0)
    allowed_scrap_rate: float = Field(default=0, ge=0)
    report_required: bool = True
    is_key_operation: bool = False
    status: str = "ACTIVE"
    remark: str | None = None


class RouteOperationRead(RouteOperationPayload):
    route_operation_id: int
    process_code: str
    process_name: str
    stamping_method: str | None = None
    work_center_code: str
    work_center_name: str
    seq_no: int
    process_id: int
    work_center_id: int
    operation_name: str
    std_setup_minutes: float
    std_cycle_seconds: float
    std_labor_cost: float
    std_machine_cost: float
    std_outsource_cost: float
    allowed_scrap_rate: float
    report_required: bool
    is_key_operation: bool
    status: str
    remark: str | None = None


class ProcessRouteRead(BaseModel):
    route_id: int
    route_code: str
    route_name: str
    product_item_id: int
    product_code: str
    product_name: str
    version_no: str
    is_default: bool
    status: str
    effective_date: date | None = None
    expire_date: date | None = None
    remark: str | None = None
    operation_count: int = 0
    operations: list[RouteOperationRead] = Field(default_factory=list)


class ProcessRouteUpsert(BaseModel):
    route_code: str | None = None
    route_name: str
    product_item_id: int
    version_no: str = "V1.0"
    is_default: bool = True
    status: str = "ACTIVE"
    effective_date: date | None = None
    expire_date: date | None = None
    remark: str | None = None
    operations: list[RouteOperationPayload]


class SalesOrderRead(BaseModel):
    order_id: int
    order_no: str
    customer_id: int
    customer_code: str
    customer_name: str
    sales_employee_id: int | None = None
    sales_employee_name: str | None = None
    order_date: date
    promised_date: date | None = None
    delivery_address: str | None = None
    total_amount: float
    status: str
    line_count: int
    mrp_count: int = 0
    purchase_order_count: int = 0
    delivery_count: int = 0
    delivery_item_count: int = 0
    work_order_count: int = 0
    can_delete: bool = False
    archive_status: str = "未生成"
    archive_version: int | None = None
    archive_created_at: datetime | None = None
    archive_error_message: str | None = None


class CustomerRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    customer_code: str
    customer_name: str
    short_name: str | None = None
    contact_name: str | None = None
    contact_phone: str | None = None
    contacts: list[dict[str, str]] = Field(default_factory=list, max_length=3)
    address: str | None = None
    credit_days: int = 0
    status: str


class CustomerCreate(BaseModel):
    customer_name: str
    short_name: str | None = None
    contact_name: str | None = None
    contact_phone: str | None = None
    contacts: list[dict[str, str]] = Field(default_factory=list, max_length=3)
    address: str | None = None
    tax_no: str | None = None
    credit_days: int = 30


class SalesOrderItemCreate(BaseModel):
    product_item_id: int
    order_qty: float
    unit_price: float
    promised_date: date | None = None
    customer_part_no: str | None = None


class SalesOrderCreate(BaseModel):
    customer_id: int
    sales_employee_id: int | None = None
    promised_date: date | None = None
    delivery_address: str | None = None
    tax_rate: float = 0
    remark: str | None = None
    items: list[SalesOrderItemCreate]


class SalesOrderItemRead(BaseModel):
    sales_order_item_id: int
    sales_order_id: int
    order_no: str
    line_no: int
    product_item_id: int
    product_code: str
    product_name: str
    customer_part_no: str | None = None
    order_qty: float
    delivered_qty: float
    unit_price: float
    line_amount: float
    promised_date: date | None = None
    status: str


class SalesOrderCreateResult(BaseModel):
    order_id: int
    order_no: str
    total_amount: float
    item_count: int
    status: str
    archive_status: str = "未生成"
    archive_version: int | None = None
    archive_error_message: str | None = None


class MaterialDemandRead(BaseModel):
    demand_id: int
    demand_no: str
    order_no: str
    material_item_id: int
    product_code: str
    product_name: str
    material_code: str
    material_name: str
    purchase_calc_mode: str
    order_qty: float
    theoretical_weight_kg: float
    planned_weight_kg: float
    shortage_weight_kg: float
    suggested_purchase_qty: float
    suggested_purchase_weight_kg: float
    status: str
    generated_at: datetime | None = None


class MrpGenerationResult(BaseModel):
    sales_order_id: int
    order_no: str
    generated_count: int
    demand_rows: list[MaterialDemandRead]
