"""Phase 6.2 sales engine DTOs."""
from __future__ import annotations

from datetime import date, datetime
from decimal import Decimal
from uuid import UUID

from pydantic import BaseModel, Field

from app.models.types import (
    ContactRoleType,
    ForecastKind,
    ForecastPeriod,
    GoalMetric,
    GoalScope,
    OpportunityStatus,
    PlaybookAssignmentStatus,
    PlaybookStepKind,
    TargetPeriod,
    WinLossOutcome,
)
from app.schemas.common import ORMBase


# ── Pipeline / Stage ─────────────────────────────────────────────────────────


class PipelineCreate(BaseModel):
    name: str = Field(max_length=255)
    code: str = Field(max_length=50)
    description: str | None = None
    sort_order: int = 0
    is_default: bool = False
    is_active: bool = True
    status: str = "active"


class PipelineUpdate(BaseModel):
    name: str | None = Field(default=None, max_length=255)
    description: str | None = None
    sort_order: int | None = None
    is_default: bool | None = None
    is_active: bool | None = None
    status: str | None = None


class PipelineRead(ORMBase):
    id: UUID
    tenant_id: UUID
    name: str
    code: str
    description: str | None
    sort_order: int
    is_default: bool
    is_active: bool
    status: str
    created_at: datetime
    updated_at: datetime


class PipelineStageCreate(BaseModel):
    pipeline_id: UUID
    name: str = Field(max_length=255)
    code: str = Field(max_length=50)
    position: int = 0
    win_probability: int = Field(default=0, ge=0, le=100)
    color: str | None = Field(default=None, max_length=20)
    is_start_stage: bool = False
    is_won_stage: bool = False
    is_lost_stage: bool = False
    is_closed_stage: bool = False
    required_fields: list[str] | None = None
    exit_validation: dict | None = None
    is_active: bool = True


class PipelineStageUpdate(BaseModel):
    name: str | None = Field(default=None, max_length=255)
    position: int | None = None
    win_probability: int | None = Field(default=None, ge=0, le=100)
    color: str | None = Field(default=None, max_length=20)
    is_start_stage: bool | None = None
    is_won_stage: bool | None = None
    is_lost_stage: bool | None = None
    is_closed_stage: bool | None = None
    required_fields: list[str] | None = None
    exit_validation: dict | None = None
    is_active: bool | None = None


class PipelineStageRead(ORMBase):
    id: UUID
    tenant_id: UUID
    pipeline_id: UUID
    name: str
    code: str
    position: int
    win_probability: int
    color: str | None
    is_start_stage: bool
    is_won_stage: bool
    is_lost_stage: bool
    is_closed_stage: bool
    required_fields: list | None
    exit_validation: dict | None
    is_active: bool
    created_at: datetime
    updated_at: datetime


# ── Opportunity ──────────────────────────────────────────────────────────────


class OpportunityCreate(BaseModel):
    name: str | None = Field(default=None, max_length=255)
    title: str | None = Field(default=None, max_length=255)
    opportunity_number: str | None = Field(default=None, max_length=50)
    pipeline_id: UUID
    stage_id: UUID
    amount: Decimal = Decimal("0")
    expected_revenue: Decimal | None = None
    currency_code: str = Field(default="IRR", max_length=3)
    probability: int = Field(default=0, ge=0, le=100)
    priority: str = "medium"
    expected_close_date: date | None = None
    organization_id: UUID | None = None
    contact_id: UUID | None = None
    lead_id: UUID | None = None
    owner_user_id: str | None = Field(default=None, max_length=100)
    description: str | None = None


class OpportunityUpdate(BaseModel):
    name: str | None = Field(default=None, max_length=255)
    title: str | None = Field(default=None, max_length=255)
    stage_id: UUID | None = None
    amount: Decimal | None = None
    expected_revenue: Decimal | None = None
    currency_code: str | None = Field(default=None, max_length=3)
    probability: int | None = Field(default=None, ge=0, le=100)
    priority: str | None = None
    expected_close_date: date | None = None
    organization_id: UUID | None = None
    contact_id: UUID | None = None
    owner_user_id: str | None = Field(default=None, max_length=100)
    description: str | None = None


class OpportunityRead(ORMBase):
    id: UUID
    tenant_id: UUID
    opportunity_number: str
    name: str
    title: str
    pipeline_id: UUID
    stage_id: UUID
    status: OpportunityStatus
    amount: Decimal
    expected_revenue: Decimal
    currency_code: str
    probability: int
    priority: str
    expected_close_date: date | None
    organization_id: UUID | None
    contact_id: UUID | None
    lead_id: UUID | None
    owner_user_id: str | None
    description: str | None
    won_at: datetime | None
    lost_at: datetime | None
    is_deleted: bool
    created_by: str | None
    updated_by: str | None
    created_at: datetime
    updated_at: datetime


class OpportunityStageChangeRequest(BaseModel):
    stage_id: UUID
    reason: str | None = None


class OpportunityWinRequest(BaseModel):
    reason_id: UUID | None = None
    category_id: UUID | None = None
    sub_category: str | None = None
    root_cause: str | None = None
    competitor_name: str | None = None
    price_factor: bool = False
    feature_gap: bool = False
    timing_factor: bool = False
    relationship_factor: bool = False
    approval_factor: bool = False
    custom_reason: str | None = None


class OpportunityLoseRequest(BaseModel):
    reason_id: UUID | None = None
    category_id: UUID | None = None
    sub_category: str | None = None
    root_cause: str | None = None
    competitor_name: str | None = None
    price_factor: bool = False
    feature_gap: bool = False
    timing_factor: bool = False
    relationship_factor: bool = False
    approval_factor: bool = False
    custom_reason: str | None = None


class StageHistoryRead(ORMBase):
    id: UUID
    tenant_id: UUID
    opportunity_id: UUID
    previous_stage_id: UUID | None
    next_stage_id: UUID
    changed_by: str | None
    changed_at: datetime
    duration_seconds: int | None
    reason: str | None
    created_at: datetime


# ── Products / Contacts / Competitors ────────────────────────────────────────


class OpportunityProductCreate(BaseModel):
    opportunity_id: UUID
    product_ref_id: str = Field(max_length=100)
    product_name: str | None = Field(default=None, max_length=255)
    quantity: Decimal = Decimal("1")
    unit_price: Decimal = Decimal("0")
    discount_percent: Decimal = Decimal("0")


class OpportunityProductRead(ORMBase):
    id: UUID
    tenant_id: UUID
    opportunity_id: UUID
    product_ref_id: str
    product_name: str | None
    quantity: Decimal
    unit_price: Decimal
    discount_percent: Decimal
    expected_revenue: Decimal
    created_at: datetime


class OpportunityContactCreate(BaseModel):
    opportunity_id: UUID
    contact_id: UUID
    role: ContactRoleType = ContactRoleType.INFLUENCER
    custom_role_label: str | None = Field(default=None, max_length=100)
    is_primary: bool = False


class OpportunityContactRead(ORMBase):
    id: UUID
    tenant_id: UUID
    opportunity_id: UUID
    contact_id: UUID
    role: ContactRoleType
    custom_role_label: str | None
    is_primary: bool
    created_at: datetime


class OpportunityCompetitorCreate(BaseModel):
    opportunity_id: UUID
    competitor_name: str = Field(max_length=255)
    strength: str | None = None
    weakness: str | None = None
    notes: str | None = None
    win_probability: int = Field(default=0, ge=0, le=100)


class OpportunityCompetitorRead(ORMBase):
    id: UUID
    tenant_id: UUID
    opportunity_id: UUID
    competitor_name: str
    strength: str | None
    weakness: str | None
    notes: str | None
    win_probability: int
    created_at: datetime


# ── Playbooks ────────────────────────────────────────────────────────────────


class PlaybookCreate(BaseModel):
    name: str = Field(max_length=255)
    code: str = Field(max_length=50)
    description: str | None = None
    version: int = 1
    pipeline_id: UUID | None = None
    is_active: bool = True


class PlaybookRead(ORMBase):
    id: UUID
    tenant_id: UUID
    name: str
    code: str
    description: str | None
    version: int
    pipeline_id: UUID | None
    is_active: bool
    is_deleted: bool
    created_at: datetime


class PlaybookStepCreate(BaseModel):
    playbook_id: UUID
    title: str = Field(max_length=255)
    step_kind: PlaybookStepKind
    position: int = 0
    is_required: bool = False
    checklist_items: list[str] | None = None
    template_body: str | None = None


class PlaybookStepRead(ORMBase):
    id: UUID
    tenant_id: UUID
    playbook_id: UUID
    title: str
    step_kind: PlaybookStepKind
    position: int
    is_required: bool
    checklist_items: list | None
    template_body: str | None
    created_at: datetime


class PlaybookAssignRequest(BaseModel):
    playbook_id: UUID
    opportunity_id: UUID | None = None
    pipeline_id: UUID | None = None


class PlaybookAssignmentRead(ORMBase):
    id: UUID
    tenant_id: UUID
    playbook_id: UUID
    opportunity_id: UUID | None
    pipeline_id: UUID | None
    status: PlaybookAssignmentStatus
    assigned_by: str | None
    completed_steps: list | None
    completion_percent: int
    completed_at: datetime | None
    created_at: datetime


class PlaybookCompleteStepRequest(BaseModel):
    step_id: UUID


# ── Win/Loss / Forecast / Goals / Targets ────────────────────────────────────


class WinLossCategoryCreate(BaseModel):
    code: str = Field(max_length=50)
    name: str = Field(max_length=150)
    parent_category_id: UUID | None = None
    is_active: bool = True


class WinLossCategoryRead(ORMBase):
    id: UUID
    tenant_id: UUID
    code: str
    name: str
    parent_category_id: UUID | None
    is_active: bool
    created_at: datetime


class WinLossReasonCreate(BaseModel):
    code: str = Field(max_length=50)
    name: str = Field(max_length=150)
    outcome: WinLossOutcome
    category_id: UUID | None = None
    is_active: bool = True


class WinLossReasonRead(ORMBase):
    id: UUID
    tenant_id: UUID
    code: str
    name: str
    outcome: WinLossOutcome
    category_id: UUID | None
    is_active: bool
    created_at: datetime


class OpportunityWinLossRead(ORMBase):
    id: UUID
    tenant_id: UUID
    opportunity_id: UUID
    outcome: WinLossOutcome
    reason_id: UUID | None
    category_id: UUID | None
    sub_category: str | None
    root_cause: str | None
    competitor_name: str | None
    price_factor: bool
    feature_gap: bool
    timing_factor: bool
    relationship_factor: bool
    approval_factor: bool
    custom_reason: str | None
    recorded_by: str | None
    recorded_at: datetime
    is_locked: bool
    created_at: datetime


class ForecastComputeRequest(BaseModel):
    name: str = Field(max_length=255)
    kind: ForecastKind = ForecastKind.WEIGHTED
    period: ForecastPeriod
    period_start: date
    period_end: date
    pipeline_id: UUID | None = None
    owner_user_id: str | None = None
    currency_code: str = "IRR"


class ForecastRead(ORMBase):
    id: UUID
    tenant_id: UUID
    name: str
    kind: ForecastKind
    period: ForecastPeriod
    period_start: date
    period_end: date
    pipeline_id: UUID | None
    owner_user_id: str | None
    pipeline_amount: Decimal
    weighted_amount: Decimal
    committed_amount: Decimal
    currency_code: str
    opportunity_count: int
    created_at: datetime


class GoalCreate(BaseModel):
    name: str = Field(max_length=255)
    scope: GoalScope
    metric: GoalMetric
    owner_user_id: str | None = None
    team_key: str | None = None
    department_key: str | None = None
    target_value: Decimal
    period_start: date
    period_end: date
    is_active: bool = True


class GoalRead(ORMBase):
    id: UUID
    tenant_id: UUID
    name: str
    scope: GoalScope
    metric: GoalMetric
    owner_user_id: str | None
    team_key: str | None
    department_key: str | None
    target_value: Decimal
    period_start: date
    period_end: date
    is_active: bool
    created_at: datetime


class TargetCreate(BaseModel):
    name: str = Field(max_length=255)
    period: TargetPeriod
    period_start: date
    period_end: date
    goal_id: UUID | None = None
    owner_user_id: str | None = None
    target_value: Decimal
    actual_value: Decimal = Decimal("0")


class TargetRead(ORMBase):
    id: UUID
    tenant_id: UUID
    name: str
    period: TargetPeriod
    period_start: date
    period_end: date
    goal_id: UUID | None
    owner_user_id: str | None
    target_value: Decimal
    actual_value: Decimal
    achievement_percent: Decimal
    created_at: datetime


class SalesAuditRead(ORMBase):
    id: UUID
    tenant_id: UUID
    entity_type: str
    entity_id: UUID
    action: str
    actor_user_id: str | None
    changes: dict | None
    message: str | None
    created_at: datetime


class SalesProcessCreate(BaseModel):
    name: str = Field(max_length=255)
    code: str = Field(max_length=50)
    description: str | None = None
    pipeline_id: UUID | None = None


class SalesProcessRead(ORMBase):
    id: UUID
    tenant_id: UUID
    name: str
    code: str
    description: str | None
    pipeline_id: UUID | None
    is_active: bool
    created_at: datetime
    updated_at: datetime
