# -*- coding: utf-8 -*-
"""小票详情加载器"""
from ..base_loader import BaseLoader
import json

class TicketLoader(BaseLoader):
    """
    Loader for parsing Ticket Detail JSON and populating DWD fact tables.
    Handles:
    - fact_order (Header)
    - fact_order_goods (Items)
    - fact_table_usage (Items)
    - fact_assistant_service (Items)
    """

    def process_tickets(self, tickets: list, store_id: int) -> tuple:
        """
        Process a batch of ticket JSONs.
        Returns (inserted_count, error_count)
        """
        inserted_count = 0
        error_count = 0

        # Prepare batch lists
        orders = []
        goods_list = []
        table_usages = []
        assistant_services = []

        for ticket in tickets:
            try:
                # 1. Parse Header (fact_order)
                root_data = ticket.get("data", {}).get("data", {})
                if not root_data:
                    continue

                order_settle_id = root_data.get("orderSettleId")
                if not order_settle_id:
                    continue

                orders.append({
                    "store_id": store_id,
                    "order_settle_id": order_settle_id,
                    "order_trade_no": 0,
                    "order_no": str(root_data.get("orderSettleNumber", "")),
                    "member_id": 0,
                    "pay_time": root_data.get("payTime"),
                    "total_amount": root_data.get("consumeMoney", 0),
                    "pay_amount": root_data.get("actualPayment", 0),
                    "discount_amount": root_data.get("memberOfferAmount", 0),
                    "coupon_amount": root_data.get("couponAmount", 0),
                    "status": "PAID",
                    "cashier_name": root_data.get("cashierName", ""),
                    "remark": root_data.get("orderRemark", ""),
                    "raw_data": json.dumps(ticket, ensure_ascii=False)
                })

                # 2. Parse Items (orderItem list)
                order_items = root_data.get("orderItem", [])
                for item in order_items:
                    order_trade_no = item.get("siteOrderId")
                    
                    # 2.1 Table Ledger
                    table_ledger = item.get("tableLedger")
                    if table_ledger:
                        table_usages.append({
                            "store_id": store_id,
                            "order_ledger_id": table_ledger.get("orderTableLedgerId"),
                            "order_settle_id": order_settle_id,
                            "table_id": table_ledger.get("siteTableId"),
                            "table_name": table_ledger.get("tableName"),
                            "start_time": table_ledger.get("chargeStartTime"),
                            "end_time": table_ledger.get("chargeEndTime"),
                            "duration_minutes": table_ledger.get("useDuration", 0),
                            "total_amount": table_ledger.get("consumptionAmount", 0),
                            "pay_amount": table_ledger.get("consumptionAmount", 0) - table_ledger.get("memberDiscountAmount", 0)
                        })

                    # 2.2 Goods Ledgers
                    goods_ledgers = item.get("goodsLedgers", [])
                    for g in goods_ledgers:
                        goods_list.append({
                            "store_id": store_id,
                            "order_goods_id": g.get("orderGoodsLedgerId"),
                            "order_settle_id": order_settle_id,
                            "order_trade_no": order_trade_no,
                            "goods_id": g.get("siteGoodsId"),
                            "goods_name": g.get("goodsName"),
                            "quantity": g.get("goodsCount", 0),
                            "unit_price": g.get("goodsPrice", 0),
                            "total_amount": g.get("ledgerAmount", 0),
                            "pay_amount": g.get("realGoodsMoney", 0)
                        })

                    # 2.3 Assistant Services
                    assistant_ledgers = item.get("assistantPlayWith", [])
                    for a in assistant_ledgers:
                        assistant_services.append({
                            "store_id": store_id,
                            "ledger_id": a.get("orderAssistantLedgerId"),
                            "order_settle_id": order_settle_id,
                            "assistant_id": a.get("assistantId"),
                            "assistant_name": a.get("ledgerName"),
                            "service_type": a.get("skillName", "Play"),
                            "start_time": a.get("ledgerStartTime"),
                            "end_time": a.get("ledgerEndTime"),
                            "duration_minutes": int(a.get("ledgerCount", 0) / 60) if a.get("ledgerCount") else 0,
                            "total_amount": a.get("ledgerAmount", 0),
                            "pay_amount": a.get("ledgerAmount", 0)
                        })

                inserted_count += 1

            except Exception as e:
                self.logger.error(f"Error parsing ticket: {e}", exc_info=True)
                error_count += 1

        # 3. Batch Insert/Upsert
        if orders:
            self._upsert_orders(orders)
        if goods_list:
            self._upsert_goods(goods_list)
        if table_usages:
            self._upsert_table_usages(table_usages)
        if assistant_services:
            self._upsert_assistant_services(assistant_services)

        return inserted_count, error_count

    def _upsert_orders(self, rows):
        sql = """
        INSERT INTO billiards.fact_order (
            store_id, order_settle_id, order_trade_no, order_no, member_id,
            pay_time, total_amount, pay_amount, discount_amount, coupon_amount,
            status, cashier_name, remark, raw_data
        ) VALUES (
            %(store_id)s, %(order_settle_id)s, %(order_trade_no)s, %(order_no)s, %(member_id)s,
            %(pay_time)s, %(total_amount)s, %(pay_amount)s, %(discount_amount)s, %(coupon_amount)s,
            %(status)s, %(cashier_name)s, %(remark)s, %(raw_data)s
        )
        ON CONFLICT (store_id, order_settle_id) DO UPDATE SET
            pay_time = EXCLUDED.pay_time,
            pay_amount = EXCLUDED.pay_amount,
            updated_at = now()
        """
        self.db.batch_execute(sql, rows)

    def _upsert_goods(self, rows):
        sql = """
        INSERT INTO billiards.fact_order_goods (
            store_id, order_goods_id, order_settle_id, order_trade_no,
            goods_id, goods_name, quantity, unit_price, total_amount, pay_amount
        ) VALUES (
            %(store_id)s, %(order_goods_id)s, %(order_settle_id)s, %(order_trade_no)s,
            %(goods_id)s, %(goods_name)s, %(quantity)s, %(unit_price)s, %(total_amount)s, %(pay_amount)s
        )
        ON CONFLICT (store_id, order_goods_id) DO UPDATE SET
            pay_amount = EXCLUDED.pay_amount
        """
        self.db.batch_execute(sql, rows)

    def _upsert_table_usages(self, rows):
        sql = """
        INSERT INTO billiards.fact_table_usage (
            store_id, order_ledger_id, order_settle_id, table_id, table_name,
            start_time, end_time, duration_minutes, total_amount, pay_amount
        ) VALUES (
            %(store_id)s, %(order_ledger_id)s, %(order_settle_id)s, %(table_id)s, %(table_name)s,
            %(start_time)s, %(end_time)s, %(duration_minutes)s, %(total_amount)s, %(pay_amount)s
        )
        ON CONFLICT (store_id, order_ledger_id) DO UPDATE SET
            pay_amount = EXCLUDED.pay_amount
        """
        self.db.batch_execute(sql, rows)

    def _upsert_assistant_services(self, rows):
        sql = """
        INSERT INTO billiards.fact_assistant_service (
            store_id, ledger_id, order_settle_id, assistant_id, assistant_name,
            service_type, start_time, end_time, duration_minutes, total_amount, pay_amount
        ) VALUES (
            %(store_id)s, %(ledger_id)s, %(order_settle_id)s, %(assistant_id)s, %(assistant_name)s,
            %(service_type)s, %(start_time)s, %(end_time)s, %(duration_minutes)s, %(total_amount)s, %(pay_amount)s
        )
        ON CONFLICT (store_id, ledger_id) DO UPDATE SET
            pay_amount = EXCLUDED.pay_amount
        """
        self.db.batch_execute(sql, rows)
