import re
import pytz
from datetime import datetime, timedelta
from pydantic import BaseModel
from typing import Optional
from bson import ObjectId
from MongoDBConnection import transactions_collection, users_collection

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')


def format_to_vn_str(dt_obj):
    """Đảm bảo format Ngày/Tháng/Năm (DD/MM/YYYY)"""
    if dt_obj.tzinfo is None:
        dt_obj = pytz.utc.localize(dt_obj)
    return dt_obj.astimezone(VN_TZ).strftime("%d/%m/%Y %H:%M:%S")


# --- SCHEMAS ---
class TopUpRequest(BaseModel):
    paymentMethod: str
    referenceId: str
    amount: float
    receiptUrl: Optional[str] = None
    id_khach_hang: str
    ten_khach_hang: str


class TopUpUpdateRequest(BaseModel):
    ticketId: str
    type: str
    status: str
    processedBy: str
    rejectReason: Optional[str] = None


# --- MODEL LOGIC ---
class TopupModel:
    @staticmethod
    def _generate_transaction_id(prefix: str, vn_now: Optional[datetime] = None) -> str:
        vn_now = vn_now or datetime.now(VN_TZ)

        # Format: TUDP-20260414115349058-0001
        timestamp_part = vn_now.strftime("%Y%m%d%H%M%S") + f"{vn_now.microsecond // 1000:03d}"
        base_prefix = f"{prefix}-{timestamp_part}-"

        regex = re.compile(rf"^{re.escape(base_prefix)}(\d{{4}})$")

        latest_docs = transactions_collection.find(
            {"id": {"$regex": rf"^{re.escape(base_prefix)}\d{{4}}$"}},
            {"id": 1}
        )

        max_seq = 0
        for doc in latest_docs:
            tx_id = str(doc.get("id") or "")
            match = regex.match(tx_id)
            if match:
                max_seq = max(max_seq, int(match.group(1)))

        next_seq = max_seq + 1

        while True:
            generated = f"{base_prefix}{str(next_seq).zfill(4)}"
            existed = transactions_collection.find_one({"id": generated}, {"_id": 1})
            if not existed:
                return generated
            next_seq += 1

    @staticmethod
    def create_topup(request: TopUpRequest):
        now_vn = datetime.now(VN_TZ)
        tx_id = TopupModel._generate_transaction_id("TUDP", now_vn)
        is_debt = str(request.paymentMethod or "").strip().lower() == "debt"

        new_doc = {
            "id": tx_id,
            "date": now_vn,
            "type": "Debt" if is_debt else "Deposit",
            "amount": f"+${request.amount:,.2f}",
            "numericAmount": request.amount,
            "status": "Pending",
            "reasonKey": f"Nạp tiền qua {request.paymentMethod}",
            "referenceId": request.referenceId,
            "paymentMethod": "Debt" if is_debt else request.paymentMethod,
            "receiptUrl": request.receiptUrl,
            "id_khach_hang": request.id_khach_hang,
            "ten_khach_hang": request.ten_khach_hang
        }
        transactions_collection.insert_one(new_doc)

        response_data = new_doc.copy()
        response_data["date"] = format_to_vn_str(now_vn)
        if "_id" in response_data:
            del response_data["_id"]
        return response_data

    @staticmethod
    def create_deduction_transaction(id_khach_hang: str, ten_khach_hang: str, amount: float, order_ids: list[str]):
        now_vn = datetime.now(VN_TZ)
        tx_id = TopupModel._generate_transaction_id("TUDD", now_vn)
        order_ref = ", ".join(order_ids)

        new_doc = {
            "id": tx_id,
            "date": now_vn,
            "type": "Deduction",
            "amount": f"-${amount:,.2f}",
            "numericAmount": amount,
            "status": "Completed",
            "reasonKey": f"Thanh toán đơn hàng {order_ref}",
            "referenceId": order_ref,
            "paymentMethod": "Balance",
            "receiptUrl": None,
            "id_khach_hang": id_khach_hang,
            "ten_khach_hang": ten_khach_hang
        }

        transactions_collection.insert_one(new_doc)

        response_data = new_doc.copy()
        response_data["date"] = format_to_vn_str(now_vn)
        if "_id" in response_data:
            del response_data["_id"]
        return response_data

    @staticmethod
    def get_topups(tx_type="all", page=1, pageSize=10, id_khach_hang=None, status=None, dateFrom=None, dateTo=None):
        query = {}
        if id_khach_hang:
            query["id_khach_hang"] = id_khach_hang

        if tx_type == "deposits":
            query["type"] = "Deposit"
        elif tx_type == "payment_requests":
            query["type"] = {"$in": ["Deposit", "Debt"]}
        elif tx_type == "deductions":
            query["type"] = "Deduction"
        elif tx_type == "debt_activity":
            query["type"] = {"$in": ["Debt", "DebtPayment"]}

        if status and status.lower() != "all":
            query["status"] = status.capitalize()

        if dateFrom or dateTo:
            date_query = {}
            if dateFrom:
                dt_from = VN_TZ.localize(datetime.strptime(dateFrom, "%Y-%m-%d"))
                date_query["$gte"] = dt_from
            if dateTo:
                dt_to = VN_TZ.localize(datetime.strptime(dateTo, "%Y-%m-%d") + timedelta(days=1, seconds=-1))
                date_query["$lte"] = dt_to
            if date_query:
                query["date"] = date_query

        cursor = (
            transactions_collection.find(query)
            .sort("date", -1)
            .skip((page - 1) * pageSize)
            .limit(pageSize)
        )
        results = list(cursor)
        total_count = transactions_collection.count_documents(query)

        formatted_data = []
        for doc in results:
            user_id_str = doc.get("id_khach_hang")
            doc["email"] = "Không rõ email"
            if user_id_str:
                try:
                    user_info = users_collection.find_one({"_id": ObjectId(user_id_str)})
                    if user_info:
                        doc["email"] = user_info.get("email", "Không rõ email")
                except Exception:
                    doc["email"] = "ID không hợp lệ"

            if isinstance(doc.get("date"), datetime):
                doc["date"] = format_to_vn_str(doc["date"])
            if "_id" in doc:
                del doc["_id"]
            formatted_data.append(doc)

        return formatted_data, total_count

    @staticmethod
    def pay_debt(user_id: str, amount: float, processed_by: str, note: str = ""):
        amount = float(amount)
        if amount <= 0:
            raise ValueError("Số tiền thanh toán phải lớn hơn 0")
        user = users_collection.find_one({"_id": ObjectId(user_id), "role": "user"})
        if not user:
            raise ValueError("Không tìm thấy khách hàng")
        current_debt = float(user.get("debtBalance", 0) or 0)
        if amount > current_debt:
            raise ValueError("Số tiền thanh toán vượt quá công nợ hiện tại")
        users_collection.update_one({"_id": ObjectId(user_id)}, {"$inc": {"debtBalance": -amount}})
        now_vn = datetime.now(VN_TZ)
        new_doc = {"id": TopupModel._generate_transaction_id("TUDPAY", now_vn), "date": now_vn, "type": "DebtPayment", "amount": f"-${amount:,.2f}", "numericAmount": amount, "status": "Completed", "reasonKey": note.strip() or "Admin ghi nhận thanh toán công nợ", "referenceId": "", "paymentMethod": "Debt", "receiptUrl": None, "id_khach_hang": user_id, "ten_khach_hang": f"{user.get('firstName', '')} {user.get('lastName', '')}".strip(), "processedBy": processed_by}
        transactions_collection.insert_one(new_doc)
        new_doc.pop("_id", None)
        new_doc["date"] = format_to_vn_str(now_vn)
        return new_doc

    @staticmethod
    def update_ticket(req: TopUpUpdateRequest):
        ticket = transactions_collection.find_one({"id": req.ticketId})
        if not ticket:
            return False, "Không tìm thấy giao dịch", 404

        if req.status == "approved" and ticket.get("status") == "Pending":
            amount_to_add = ticket.get("numericAmount", 0)
            user_id_str = ticket.get("id_khach_hang")
            if not user_id_str:
                return False, "Không thể duyệt: giao dịch thiếu thông tin khách hàng (id_khach_hang rỗng)", 400
            try:
                increments = {"balance": amount_to_add}
                if ticket.get("type") == "Debt":
                    increments["debtBalance"] = amount_to_add
                result = users_collection.update_one(
                    {"_id": ObjectId(user_id_str)},
                    {"$inc": increments}
                )
                if result.matched_count == 0:
                    return False, f"Không tìm thấy user với id '{user_id_str}', không thể cộng tiền", 400
            except Exception as e:
                return False, f"Lỗi khi cộng tiền: {e}", 500

        update_fields = {
            "status": req.status.capitalize() if req.status != "resolved" else "Resolved",
            "processedBy": req.processedBy
        }

        if req.status == "rejected" and req.rejectReason:
            update_fields["rejectReason"] = req.rejectReason

        transactions_collection.update_one({"id": req.ticketId}, {"$set": update_fields})
        return True, "Đã duyệt và cập nhật thành công", 200
