from datetime import datetime, timezone
from sqlalchemy.orm import Session
from sqlalchemy import and_,update
from core.config import get_db
from core.security.exceptions import CoreDBError, GenericError
from models.discount_coupon import DiscountCoupon
from models.payment import Payment
from schema.discount_coupon import (
    DiscountCouponCreate,
    DiscountCouponUpdate,
    DiscountCouponResponse
)

class DiscountCouponService:
    
    def create_coupon(self, request):
        with get_db() as db:
            payload = request.model_dump()
            print(payload)
            try:
                # Check if coupon code already exists
                if db.query(DiscountCoupon).filter(
                    DiscountCoupon.code == payload['code'],
                    DiscountCoupon.deleted_at.is_(None)
                ).first():
                    raise GenericError(status_code=400, exc="Coupon code already exists")
                
                # Validate dates
                if payload['start_date'] >= payload['end_date']:
                    raise GenericError(status_code=400, exc="End date must be after start date")
                
                instance = DiscountCoupon(**payload)
                db.add(instance)
                db.commit()
                db.refresh(instance)
                return instance
            except Exception as e:
                db.rollback()
                raise CoreDBError(f"Could not create new discount coupon: {e}")

    def list_all(self, status=None):
        with get_db() as db:
            query = db.query(DiscountCoupon).filter(
                DiscountCoupon.deleted_at.is_(None)
            )
            
            if status is not None:
                query = query.filter(DiscountCoupon.status == status)
                
            return query.all()

    def get_by_id(self, coupon_id: int):
        with get_db() as db:
            record = db.query(DiscountCoupon).where(
                DiscountCoupon.id == coupon_id,
                DiscountCoupon.deleted_at.is_(None)
            ).first()

            if not record:
                raise GenericError(status_code=404, exc="Discount coupon not found")
            return DiscountCouponResponse.model_validate(record).model_dump()

    def update_coupon(self, coupon_id: int, request):
        payload = request.model_dump(exclude=['id'])
        with get_db() as db:
            result = db.query(DiscountCoupon).filter(
                DiscountCoupon.id == coupon_id,
                DiscountCoupon.deleted_at.is_(None)
            ).update(payload, synchronize_session="fetch")
            
            db.commit()
            if result == 0:
                raise GenericError(status_code=422, exc="Could not update discount coupon")
            return self.get_by_id(coupon_id)
            

    def toggle_status(self, coupon_id: int):
        with get_db() as db:
            db.execute(
                update(DiscountCoupon)
                .where(DiscountCoupon.id == coupon_id)
                .values(status=~DiscountCoupon.status)
            )
            db.commit()

    def delete_coupon(self, coupon_id: int):
        with get_db() as db:
            coupon = db.query(DiscountCoupon).where(
                DiscountCoupon.id == coupon_id,
                DiscountCoupon.deleted_at.is_(None)
            ).first()

            if not coupon:
                raise GenericError(status_code=404, exc="Discount coupon not found")

            coupon.deleted_at = datetime.now(timezone.utc)
            db.commit()
            return {"message": "Discount coupon deleted successfully"}

    def validate_coupon(self, code: str, cart_value: float = None, user_id: int = None):
        with get_db() as db:
            now = datetime.now(timezone.utc)
            coupon = db.query(DiscountCoupon).filter(
                DiscountCoupon.code == code,
                DiscountCoupon.deleted_at.is_(None),
                DiscountCoupon.status == True,
                DiscountCoupon.start_date <= now,
                DiscountCoupon.end_date >= now
            ).first()

            if not coupon:
                return {"valid": False, "message": "Invalid or inactive coupon"}

            # Check minimum cart value if provided
            if cart_value is not None and coupon.min_cart_value \
                    and cart_value < coupon.min_cart_value:
                return {
                    "valid": False,
                    "message": f"Cart value must be at least {coupon.min_cart_value}"
                }

            # Check usage per customer limit if user_id is provided
            if user_id is not None and coupon.uses_per_customer:
                usage_count = db.query(Payment).filter(
                    Payment.discount_coupon_id == coupon.id,
                    Payment.created_by == user_id,
                    Payment.is_payment_completed == True
                ).count()
                
                if usage_count >= coupon.uses_per_customer:
                    return {
                        "valid": False,
                        "message": f"You have exceeded the maximum usage limit of {coupon.uses_per_customer} for this coupon"
                    }

            return {
                "valid": True,
                "coupon": DiscountCouponResponse.model_validate(coupon).model_dump(),
                "message": "Coupon is valid"
            }