# app/services/invoice_service.py
import logging
from datetime import date, datetime
from fastapi import BackgroundTasks
from pymongo.collection import Collection
from ...models.saas.invoices import SaaSInvoiceCreate, SaaSInvoiceDB, SaaSInvoiceUpdate
from ...models.common import InvoiceStatus
from ....db import database
from typing import Optional
# from ...libraries.email_templates import (
#     invoice_created_email,
#     send_invoice_paid_email,
#     send_invoice_reminder_email
# )
from bson import ObjectId

logger = logging.getLogger(__name__)

INVOICE_COLLECTION = "saas_invoices"

# async def create_invoice_service(
#     invoice_in: SaaSInvoiceCreate,
#     db: database.MongoDB,
#     background_tasks: BackgroundTasks
# ) -> SaaSInvoiceDB:
#     coll: Collection = db[INVOICE_COLLECTION]
#     data = invoice_in.dict()
#     # result = coll.insert_one(data)
#     # invoice_id = str(result.inserted_id)
#     data["created_at"] = now
#     data["invoice_id"] = str(ObjectId())  # optional: manually create invoice_id
#     result = coll.insert_one({**data, "_id": ObjectId(data["invoice_id"])})


#     # schedule email
#     background_tasks.add_task(
#         send_invoice_created_email,
#         invoice_id=invoice_id,
#         to_account=invoice_in.account_id,
#         title=invoice_in.invoice_title,
#         amount=invoice_in.amount,
#         due_date=invoice_in.due_date
#     )
#     return SaaSInvoiceDB(**data, invoice_id=invoice_id)

# async def create_invoice_service(
#     invoice_in: SaaSInvoiceCreate,
#     db: database.MongoDB,
#     background_tasks: BackgroundTasks
# ) -> SaaSInvoiceDB:
#     coll: Collection = db[INVOICE_COLLECTION]

#     now = datetime.utcnow()
#     invoice_id = str(ObjectId())

#     data = invoice_in.dict()
#     data["created_date"] = now
#     data["invoice_id"] = invoice_id

#     coll.insert_one({**data, "_id": ObjectId(invoice_id)})

#     # schedule email (optional if implemented)
#     background_tasks.add_task(
#         send_invoice_created_email,
#         invoice_id=invoice_id,
#         to_account=invoice_in.account_id,
#         title=invoice_in.invoice_title,
#         amount=invoice_in.amount,
#         due_date=invoice_in.due_date
#     )

#     return SaaSInvoiceDB(**data)

def ensure_datetime(value):
    """Convert date to datetime if needed."""
    if isinstance(value, datetime):
        return value
    if isinstance(value, date):
        return datetime.combine(value, datetime.min.time())
    return value

def ensure_enum(value):
    """Convert Enum -> string value."""
    return value.value if hasattr(value, "value") else value

async def create_invoice_service(
    invoice_in: SaaSInvoiceCreate,
    db: database.MongoDB,
    background_tasks: BackgroundTasks
) -> SaaSInvoiceDB:
    coll: Collection = db[INVOICE_COLLECTION]

    now = datetime.utcnow()
    invoice_id = str(ObjectId())

    # normalize input
    data = invoice_in.dict()
    data["invoice_date"] = ensure_datetime(data.get("invoice_date"))
    data["due_date"] = ensure_datetime(data.get("due_date"))
    data["status"] = ensure_enum(data.get("status"))
    data["invoice_type"] = ensure_enum(data.get("invoice_type"))

    # system fields
    data["created_date"] = now
    data["updated_date"] = now
    data["invoice_id"] = invoice_id

    # insert into mongo
    coll.insert_one({**data, "_id": ObjectId(invoice_id)})

    # schedule email (if enabled)
    # background_tasks.add_task(
    #     send_invoice_created_email,
    #     invoice_id=invoice_id,
    #     to_account=invoice_in.account_id,
    #     title=invoice_in.invoice_title,
    #     amount=invoice_in.amount,
    #     due_date=data["due_date"]
    # )

    return SaaSInvoiceDB(**data)

# async def list_invoices_service(skip: int, limit: int, q: Optional[str], db: database.MongoDB, account_id: str = None
# ) -> list[SaaSInvoiceDB]:
#     coll: Collection = db[INVOICE_COLLECTION]
#     query = {"account_id": account_id} if account_id else {}
#     docs = list(coll.find(query).sort("invoice_date", -1))
#     return [SaaSInvoiceDB(**doc, invoice_id=str(doc["_id"])) for doc in docs]

async def list_invoices_service(
    skip: int,
    limit: int,
    q: Optional[str],
    status: Optional[str],
    created_date_from: Optional[str],
    created_date_to: Optional[str],
    db: database.MongoDB,
    account_id: str = None
) -> dict:
    coll: Collection = db[INVOICE_COLLECTION]
    query = {"account_id": account_id} if account_id else {}

    if status:
        query["status"] = status

    if q:
        regex_query = {"$regex": q, "$options": "i"}
        query["$or"] = [
            {"invoice_title": regex_query}
        ]

    if created_date_from or created_date_to:
        date_filter = {}
        if created_date_from:
            date_filter["$gte"] = datetime.strptime(created_date_from, "%Y-%m-%d")
        if created_date_to:
            date_filter["$lte"] = datetime.strptime(created_date_to, "%Y-%m-%d")
        query["invoice_date"] = date_filter

    total_count = coll.count_documents(query)

    cursor = coll.find(query).sort("invoice_date", -1).skip(skip).limit(limit)
    docs = list(cursor)

    invoices = []
    for doc in docs:
        doc["invoice_id"] = str(doc["_id"])   # normalize id
        doc.pop("_id", None)
        invoices.append(SaaSInvoiceDB(**doc).dict())

    return {
        "total_count": total_count,
        "invoices": invoices
    }

# async def get_invoice_service(
#     invoice_id: str, db: database.MongoDB
# ) -> SaaSInvoiceDB:
#     coll: Collection = db[INVOICE_COLLECTION]
#     doc = coll.find_one({"_id": database.str_to_objectid(invoice_id)})
#     if not doc:
#         raise ValueError("Invoice not found")
#     return SaaSInvoiceDB(**doc, invoice_id=str(doc["_id"]))

async def get_invoice_service(
    invoice_id: str, db: database.MongoDB
) -> SaaSInvoiceDB:
    coll: Collection = db[INVOICE_COLLECTION]

    # Convert string -> ObjectId safely
    try:
        oid = ObjectId(invoice_id)
    except Exception:
        raise ValueError("Invalid invoice ID")

    doc = coll.find_one({"_id": oid})
    if not doc:
        raise ValueError("Invoice not found")

    # Normalize fields
    doc["invoice_id"] = str(doc["_id"])
    doc.pop("_id", None)

    return SaaSInvoiceDB(**doc)

async def update_invoice_status_service(
    invoice_id: str,
    update: SaaSInvoiceUpdate,
    db: database.MongoDB,
    background_tasks: BackgroundTasks
) -> SaaSInvoiceDB:
    coll: Collection = db[INVOICE_COLLECTION]
    coll.update_one(
        {"_id": database.str_to_objectid(invoice_id)},
        {"$set": {"status": update.status}}
    )
    updated = coll.find_one({"_id": database.str_to_objectid(invoice_id)})
    invoice = SaaSInvoiceDB(**updated, invoice_id=invoice_id)

    if update.status == InvoiceStatus.PAID:
        background_tasks.add_task(
            send_invoice_paid_email,
            invoice_id=invoice_id,
            to_account=invoice.account_id,
            amount=invoice.amount
        )
    return invoice

async def run_due_reminders(db: database.MongoDB, background_tasks: BackgroundTasks):
    """Mark overdue + send reminders for upcoming due dates."""
    coll: Collection = db[INVOICE_COLLECTION]
    today = date.today()
    # mark overdue
    coll.update_many(
        {"due_date": {"$lt": today}, "status": {"$ne": InvoiceStatus.PAID}},
        {"$set": {"status": InvoiceStatus.OVERDUE}}
    )
    # find due tomorrow
    tomorrow = today
    cursor = coll.find({"due_date": tomorrow, "status": {"$ne": InvoiceStatus.PAID}})
    for doc in cursor:
        invoice_id = str(doc["_id"])
        background_tasks.add_task(
            send_invoice_reminder_email,
            invoice_id=invoice_id,
            to_account=doc["account_id"],
            due_date=doc["due_date"]
        )
