from enum import Enum
from typing import Any, Dict, List, Optional
from pydantic import BaseModel


class ProductCategory(str, Enum):
    controller = "controller"
    striker = "striker"
    clock = "clock"
    part = "part"
    repair_service = "repair_service"


class CostLineItem(BaseModel):
    name: str
    quantity: float = 1
    price: float = 0.0


class ProductCosts(BaseModel):
    labor_hours: Optional[float] = None
    labor_rate: Optional[float] = None
    items: List[CostLineItem] = []
    total: Optional[float] = None


class ProductStock(BaseModel):
    on_hand: int = 0
    reserved: int = 0
    available: int = 0


class ProductCreate(BaseModel):
    name: str
    sku: Optional[str] = None
    category: ProductCategory
    description: Optional[str] = None
    name_en: Optional[str] = None
    name_gr: Optional[str] = None
    description_en: Optional[str] = None
    description_gr: Optional[str] = None
    price: float
    currency: str = "EUR"
    costs: Optional[ProductCosts] = None
    stock: Optional[ProductStock] = None
    active: bool = True
    status: str = "active"  # active | discontinued | planned
    photo_url: Optional[str] = None


class ProductUpdate(BaseModel):
    name: Optional[str] = None
    sku: Optional[str] = None
    category: Optional[ProductCategory] = None
    description: Optional[str] = None
    name_en: Optional[str] = None
    name_gr: Optional[str] = None
    description_en: Optional[str] = None
    description_gr: Optional[str] = None
    price: Optional[float] = None
    currency: Optional[str] = None
    costs: Optional[ProductCosts] = None
    stock: Optional[ProductStock] = None
    active: Optional[bool] = None
    status: Optional[str] = None
    photo_url: Optional[str] = None


class ProductInDB(ProductCreate):
    id: str
    created_at: str
    updated_at: str


class ProductListResponse(BaseModel):
    products: List[ProductInDB]
    total: int


# ── Customers ────────────────────────────────────────────────────────────────

class ContactType(str, Enum):
    email = "email"
    phone = "phone"
    whatsapp = "whatsapp"
    other = "other"


class CustomerContact(BaseModel):
    type: ContactType
    label: str
    value: str
    primary: bool = False


class CustomerNote(BaseModel):
    text: str
    by: str
    at: str


class OwnedItemType(str, Enum):
    console_device = "console_device"
    product = "product"
    freetext = "freetext"


class OwnedItem(BaseModel):
    type: OwnedItemType
    # console_device fields
    device_id: Optional[str] = None
    label: Optional[str] = None
    # product fields
    product_id: Optional[str] = None
    product_name: Optional[str] = None
    quantity: Optional[int] = None
    serial_numbers: Optional[List[str]] = None
    # freetext fields
    description: Optional[str] = None
    serial_number: Optional[str] = None
    notes: Optional[str] = None


class CustomerLocation(BaseModel):
    address: Optional[str] = None
    city: Optional[str] = None
    postal_code: Optional[str] = None
    region: Optional[str] = None
    country: Optional[str] = None


# ── New customer status models ────────────────────────────────────────────────

class TechnicalIssue(BaseModel):
    active: bool = True
    opened_date: str  # ISO string
    resolved_date: Optional[str] = None
    note: str
    opened_by: str
    resolved_by: Optional[str] = None


class InstallSupportEntry(BaseModel):
    active: bool = True
    opened_date: str  # ISO string
    resolved_date: Optional[str] = None
    note: str
    opened_by: str
    resolved_by: Optional[str] = None


class TransactionEntry(BaseModel):
    date: str  # ISO string
    flow: str  # "invoice" | "payment" | "refund" | "credit"
    payment_type: Optional[str] = None  # "cash" | "bank_transfer" | "card" | "paypal" — null for invoices
    category: str  # "full_payment" | "advance" | "installment"
    amount: float
    currency: str = "EUR"
    invoice_ref: Optional[str] = None
    order_ref: Optional[str] = None
    recorded_by: str
    note: str = ""


# Lightweight summary stored on customer doc for fast CustomerList expanded view
class CrmSummary(BaseModel):
    active_order_status: Optional[str] = None
    active_order_status_date: Optional[str] = None
    active_order_title: Optional[str] = None
    active_issues_count: int = 0
    latest_issue_date: Optional[str] = None
    active_support_count: int = 0
    latest_support_date: Optional[str] = None


class CustomerCreate(BaseModel):
    title: Optional[str] = None
    name: str
    surname: Optional[str] = None
    organization: Optional[str] = None
    religion: Optional[str] = None
    contacts: List[CustomerContact] = []
    notes: List[CustomerNote] = []
    location: Optional[CustomerLocation] = None
    language: str = "el"
    tags: List[str] = []
    owned_items: List[OwnedItem] = []
    linked_user_ids: List[str] = []
    nextcloud_folder: Optional[str] = None
    folder_id: Optional[str] = None
    relationship_status: str = "lead"
    technical_issues: List[Dict[str, Any]] = []
    install_support: List[Dict[str, Any]] = []
    transaction_history: List[Dict[str, Any]] = []
    crm_summary: Optional[Dict[str, Any]] = None


class CustomerUpdate(BaseModel):
    title: Optional[str] = None
    name: Optional[str] = None
    surname: Optional[str] = None
    organization: Optional[str] = None
    religion: Optional[str] = None
    contacts: Optional[List[CustomerContact]] = None
    notes: Optional[List[CustomerNote]] = None
    location: Optional[CustomerLocation] = None
    language: Optional[str] = None
    tags: Optional[List[str]] = None
    owned_items: Optional[List[OwnedItem]] = None
    linked_user_ids: Optional[List[str]] = None
    nextcloud_folder: Optional[str] = None
    relationship_status: Optional[str] = None
    # folder_id intentionally excluded from update — set once at creation


class CustomerInDB(CustomerCreate):
    id: str
    created_at: str
    updated_at: str


class CustomerListResponse(BaseModel):
    customers: List[CustomerInDB]
    total: int


# ── Orders ───────────────────────────────────────────────────────────────────

class OrderStatus(str, Enum):
    negotiating = "negotiating"
    awaiting_quotation = "awaiting_quotation"
    awaiting_customer_confirmation = "awaiting_customer_confirmation"
    awaiting_fulfilment = "awaiting_fulfilment"
    awaiting_payment = "awaiting_payment"
    manufacturing = "manufacturing"
    shipped = "shipped"
    installed = "installed"
    declined = "declined"
    complete = "complete"


class OrderPaymentStatus(BaseModel):
    required_amount: float = 0
    received_amount: float = 0
    balance_due: float = 0
    advance_required: bool = False
    advance_amount: Optional[float] = None
    payment_complete: bool = False


class OrderTimelineEvent(BaseModel):
    date: str  # ISO string
    type: str  # "quote_request" | "quote_sent" | "quote_accepted" | "quote_declined"
               # | "mfg_started" | "mfg_complete" | "order_shipped" | "installed"
               # | "payment_received" | "invoice_sent" | "note"
    note: str = ""
    updated_by: str


class OrderDiscount(BaseModel):
    type: str  # "percentage" | "fixed"
    value: float = 0
    reason: Optional[str] = None


class OrderShipping(BaseModel):
    method: Optional[str] = None
    tracking_number: Optional[str] = None
    carrier: Optional[str] = None
    shipped_at: Optional[str] = None
    delivered_at: Optional[str] = None
    destination: Optional[str] = None


class OrderItem(BaseModel):
    type: str  # console_device | product | freetext
    product_id: Optional[str] = None
    product_name: Optional[str] = None
    description: Optional[str] = None
    quantity: int = 1
    unit_price: float = 0.0
    serial_numbers: List[str] = []


class OrderCreate(BaseModel):
    customer_id: str
    order_number: Optional[str] = None
    title: Optional[str] = None
    created_by: Optional[str] = None
    status: OrderStatus = OrderStatus.negotiating
    status_updated_date: Optional[str] = None
    status_updated_by: Optional[str] = None
    items: List[OrderItem] = []
    subtotal: float = 0
    discount: Optional[OrderDiscount] = None
    total_price: float = 0
    currency: str = "EUR"
    shipping: Optional[OrderShipping] = None
    payment_status: Optional[Dict[str, Any]] = None
    invoice_path: Optional[str] = None
    notes: Optional[str] = None
    timeline: List[Dict[str, Any]] = []


class OrderUpdate(BaseModel):
    order_number: Optional[str] = None
    title: Optional[str] = None
    status: Optional[OrderStatus] = None
    status_updated_date: Optional[str] = None
    status_updated_by: Optional[str] = None
    items: Optional[List[OrderItem]] = None
    subtotal: Optional[float] = None
    discount: Optional[OrderDiscount] = None
    total_price: Optional[float] = None
    currency: Optional[str] = None
    shipping: Optional[OrderShipping] = None
    payment_status: Optional[Dict[str, Any]] = None
    invoice_path: Optional[str] = None
    notes: Optional[str] = None


class OrderInDB(OrderCreate):
    id: str
    created_at: str
    updated_at: str


class OrderListResponse(BaseModel):
    orders: List[OrderInDB]
    total: int


# ── Comms Log ─────────────────────────────────────────────────────────────────

class CommType(str, Enum):
    email = "email"
    whatsapp = "whatsapp"
    call = "call"
    sms = "sms"
    note = "note"
    in_person = "in_person"


class CommDirection(str, Enum):
    inbound = "inbound"
    outbound = "outbound"
    internal = "internal"


class CommAttachment(BaseModel):
    filename: str
    nextcloud_path: Optional[str] = None
    content_type: Optional[str] = None
    size: Optional[int] = None


class CommCreate(BaseModel):
    customer_id: Optional[str] = None
    type: CommType
    mail_account: Optional[str] = None
    direction: CommDirection
    subject: Optional[str] = None
    body: Optional[str] = None
    body_html: Optional[str] = None
    attachments: List[CommAttachment] = []
    ext_message_id: Optional[str] = None
    from_addr: Optional[str] = None
    to_addrs: Optional[List[str]] = None
    logged_by: Optional[str] = None
    occurred_at: Optional[str] = None  # defaults to now if not provided


class CommUpdate(BaseModel):
    type: Optional[CommType] = None
    direction: Optional[CommDirection] = None
    subject: Optional[str] = None
    body: Optional[str] = None
    logged_by: Optional[str] = None
    occurred_at: Optional[str] = None


class CommInDB(BaseModel):
    id: str
    customer_id: Optional[str] = None
    type: CommType
    mail_account: Optional[str] = None
    direction: CommDirection
    subject: Optional[str] = None
    body: Optional[str] = None
    body_html: Optional[str] = None
    attachments: List[CommAttachment] = []
    ext_message_id: Optional[str] = None
    from_addr: Optional[str] = None
    to_addrs: Optional[List[str]] = None
    logged_by: Optional[str] = None
    occurred_at: str
    created_at: str
    is_important: bool = False
    is_read: bool = False


class CommListResponse(BaseModel):
    entries: List[CommInDB]
    total: int


# ── Media ─────────────────────────────────────────────────────────────────────

class MediaDirection(str, Enum):
    received = "received"
    sent = "sent"
    internal = "internal"


class MediaCreate(BaseModel):
    customer_id: Optional[str] = None
    order_id: Optional[str] = None
    filename: str
    nextcloud_path: str
    mime_type: Optional[str] = None
    direction: Optional[MediaDirection] = None
    tags: List[str] = []
    uploaded_by: Optional[str] = None
    thumbnail_path: Optional[str] = None


class MediaInDB(BaseModel):
    id: str
    customer_id: Optional[str] = None
    order_id: Optional[str] = None
    filename: str
    nextcloud_path: str
    mime_type: Optional[str] = None
    direction: Optional[MediaDirection] = None
    tags: List[str] = []
    uploaded_by: Optional[str] = None
    created_at: str
    thumbnail_path: Optional[str] = None


class MediaListResponse(BaseModel):
    items: List[MediaInDB]
    total: int
