import os
import json
from datetime import datetime, timedelta, timezone
from flask import Blueprint, request, jsonify, session

mobile_api_bp = Blueprint('mobile_api', __name__, url_prefix='/api/mobile')

def register_mobile_api(app, db, models, helpers):
    """Registers all Flutter Mobile App REST API endpoints onto the Flask application."""
    
    User = models['User']
    Shop = models['Shop']
    Product = models['Product']
    Customer = models['Customer']
    Supplier = models['Supplier']
    Invoice = models.get('Invoice')
    InvoiceItem = models.get('InvoiceItem')
    Sale = Invoice
    SaleItem = InvoiceItem
    CustomerPayment = models.get('CustomerPayment')
    Purchase = models['Purchase']
    Expense = models['Expense']
    Coupon = models.get('Coupon')
    bangladesh_time = helpers['bangladesh_time']
    safe_float = helpers.get('safe_float', lambda x, d=0.0: float(x) if x else d)
    safe_int = helpers.get('safe_int', lambda x, d=0: int(x) if x else d)

    def get_shop_id():
        s = Shop.query.first()
        return s.id if s else 1

    @mobile_api_bp.route('/health', methods=['GET'])
    def health_check():
        shop = Shop.query.first()
        return jsonify({
            'status': 'ok',
            'shop_name': shop.shop_name if shop else 'Shop Manager POS',
            'online': True,
            'timestamp': bangladesh_time().isoformat()
        })

    @mobile_api_bp.route('/login', methods=['POST'])
    def mobile_login():
        data = request.get_json(silent=True) or request.form
        identifier = str(data.get('username') or data.get('identifier') or '').strip()
        password = str(data.get('password') or '').strip()

        if not identifier or not password:
            return jsonify({'success': False, 'message': 'Username/Email/Phone and password are required'}), 400

        user = User.query.filter(
            (User.username.ilike(identifier)) |
            (User.email.ilike(identifier)) |
            (User.phone == identifier)
        ).first()

        if not user or not user.check_password(password):
            return jsonify({'success': False, 'message': 'Invalid credentials. Please try again.'}), 401

        shop = user.shop or Shop.query.first()
        now_bd = bangladesh_time()
        days_left = max(0, (shop.license_expires_at.date() - now_bd.date()).days) if shop and shop.license_expires_at else 30

        return jsonify({
            'success': True,
            'message': 'Login successful',
            'token': f"mobile_token_{user.id}_{int(now_bd.timestamp())}",
            'user': {
                'id': user.id,
                'username': user.username,
                'email': user.email or '',
                'phone': user.phone or '',
                'role': user.role
            },
            'shop': {
                'id': shop.id if shop else 1,
                'name': shop.shop_name if shop else 'Shop Manager POS',
                'owner_name': shop.owner_name if shop else '',
                'phone': shop.phone if shop else '',
                'subscription_plan': shop.subscription_plan if shop else 'Free Trial',
                'license_days_left': days_left
            }
        })

    @mobile_api_bp.route('/dashboard', methods=['GET'])
    def mobile_dashboard():
        now_bd = bangladesh_time()
        today_start = now_bd.replace(hour=0, minute=0, second=0, microsecond=0)

        today_sales = Sale.query.filter(Sale.created_at >= today_start).all()
        today_sales_total = sum(float(s.total_amount or 0.0) for s in today_sales)
        today_sales_count = len(today_sales)

        all_products = Product.query.all()
        total_products = len(all_products)
        low_stock_products = [p for p in all_products if (getattr(p, 'stock', 0) or 0) <= (getattr(p, 'low_stock_limit', 5) or 5)]
        low_stock_count = len(low_stock_products)

        customers = Customer.query.all()
        total_due_balance = sum(float(getattr(c, 'due_balance', 0.0) or 0.0) for c in customers)

        shop = Shop.query.first()
        days_left = max(0, (shop.license_expires_at.date() - now_bd.date()).days) if shop and shop.license_expires_at else 30

        return jsonify({
            'success': True,
            'today_sales_total': today_sales_total,
            'today_sales_count': today_sales_count,
            'total_products': total_products,
            'low_stock_count': low_stock_count,
            'total_due_balance': total_due_balance,
            'license_days_left': days_left,
            'shop_name': shop.shop_name if shop else 'Shop POS'
        })

    @mobile_api_bp.route('/products', methods=['GET'])
    def mobile_products():
        products = Product.query.order_by(Product.name.asc()).all()
        categories = list(set(p.category for p in products if getattr(p, 'category', None)))

        return jsonify({
            'success': True,
            'categories': [{'id': idx+1, 'name': cat} for idx, cat in enumerate(categories)],
            'products': [{
                'id': p.id,
                'name': p.name,
                'barcode': getattr(p, 'barcode', '') or '',
                'category_name': getattr(p, 'category', 'General') or 'General',
                'buy_price': float(getattr(p, 'buy_price', 0.0) or 0.0),
                'price': float(getattr(p, 'sell_price', getattr(p, 'price', 0.0)) or 0.0),
                'stock': getattr(p, 'stock', 0) or 0,
                'unit': getattr(p, 'unit', 'pcs') or 'pcs',
                'low_stock_limit': getattr(p, 'low_stock_limit', 5) or 5,
                'is_low_stock': (getattr(p, 'stock', 0) or 0) <= (getattr(p, 'low_stock_limit', 5) or 5)
            } for p in products]
        })

    @mobile_api_bp.route('/products/barcode/<path:barcode>', methods=['GET'])
    def mobile_product_by_barcode(barcode):
        barcode = barcode.strip()
        product = Product.query.filter(
            (Product.barcode == barcode) | (Product.id == safe_int(barcode))
        ).first()

        if not product:
            return jsonify({'success': False, 'message': f"No product found for barcode '{barcode}'"}), 404

        return jsonify({
            'success': True,
            'product': {
                'id': product.id,
                'name': product.name,
                'barcode': getattr(product, 'barcode', '') or '',
                'category_name': getattr(product, 'category', 'General') or 'General',
                'buy_price': float(getattr(product, 'buy_price', 0.0) or 0.0),
                'price': float(getattr(product, 'sell_price', getattr(product, 'price', 0.0)) or 0.0),
                'stock': getattr(product, 'stock', 0) or 0,
                'unit': getattr(product, 'unit', 'pcs') or 'pcs'
            }
        })

    @mobile_api_bp.route('/products/add', methods=['POST'])
    def mobile_add_product():
        data = request.get_json(silent=True) or request.form
        name = str(data.get('name') or '').strip()
        if not name:
            return jsonify({'success': False, 'message': 'Product name is required'}), 400

        barcode = str(data.get('barcode') or '').strip()
        buy_price = safe_float(data.get('buy_price'), 0.0)
        sell_price = safe_float(data.get('sell_price') or data.get('price'), 0.0)
        stock = safe_int(data.get('stock'), 0)
        category = str(data.get('category') or data.get('category_name') or 'General').strip()
        unit = str(data.get('unit') or 'pcs').strip()

        if barcode:
            dup = Product.query.filter_by(barcode=barcode).first()
            if dup:
                return jsonify({'success': False, 'message': f"Barcode '{barcode}' is already assigned to '{dup.name}'"}), 400

        p = Product(
            shop_id=get_shop_id(),
            name=name,
            barcode=barcode or None,
            buy_price=buy_price,
            sell_price=sell_price,
            stock=stock,
            category=category,
            unit=unit
        )
        db.session.add(p)
        db.session.commit()

        return jsonify({
            'success': True,
            'message': f"Product '{name}' created successfully!",
            'product_id': p.id
        })

    @mobile_api_bp.route('/products/edit/<int:product_id>', methods=['POST'])
    def mobile_edit_product(product_id):
        p = Product.query.get(product_id)
        if not p:
            return jsonify({'success': False, 'message': 'Product not found'}), 404

        data = request.get_json(silent=True) or request.form
        p.name = str(data.get('name') or p.name).strip()
        p.barcode = str(data.get('barcode') or '').strip() or None
        p.buy_price = safe_float(data.get('buy_price'), getattr(p, 'buy_price', 0.0))
        p.sell_price = safe_float(data.get('sell_price') or data.get('price'), getattr(p, 'sell_price', 0.0))
        p.stock = safe_int(data.get('stock'), getattr(p, 'stock', 0))
        p.unit = str(data.get('unit') or getattr(p, 'unit', 'pcs')).strip()
        p.category = str(data.get('category') or getattr(p, 'category', 'General')).strip()

        db.session.commit()
        return jsonify({'success': True, 'message': f"Product '{p.name}' updated successfully!"})

    @mobile_api_bp.route('/products/delete/<int:product_id>', methods=['POST'])
    def mobile_delete_product(product_id):
        p = Product.query.get(product_id)
        if not p:
            return jsonify({'success': False, 'message': 'Product not found'}), 404

        try:
            has_invoices = InvoiceItem.query.filter_by(product_id=product_id).first() if InvoiceItem else None
            if has_invoices:
                p.active = False
                db.session.commit()
                return jsonify({'success': True, 'message': f"Product '{p.name}' archived (soft deleted)!"})
            else:
                db.session.delete(p)
                db.session.commit()
                return jsonify({'success': True, 'message': f"Product '{p.name}' deleted successfully!"})
        except Exception as ex:
            db.session.rollback()
            p.active = False
            db.session.commit()
            return jsonify({'success': True, 'message': f"Product '{p.name}' deactivated!"})

    @mobile_api_bp.route('/customers', methods=['GET'])
    def mobile_customers():
        customers = Customer.query.order_by(Customer.name.asc()).all()
        return jsonify({
            'success': True,
            'customers': [{
                'id': c.id,
                'name': c.name,
                'phone': getattr(c, 'phone', '') or '',
                'address': getattr(c, 'address', '') or '',
                'due_balance': float(getattr(c, 'due_balance', 0.0) or 0.0),
                'advance_balance': float(getattr(c, 'advance_balance', 0.0) or 0.0)
            } for c in customers]
        })

    @mobile_api_bp.route('/customers/add', methods=['POST'])
    def mobile_add_customer():
        data = request.get_json(silent=True) or request.form
        name = str(data.get('name') or '').strip()
        if not name:
            return jsonify({'success': False, 'message': 'Customer name is required'}), 400

        phone = str(data.get('phone') or '').strip()
        address = str(data.get('address') or '').strip()
        due_balance = safe_float(data.get('due_balance'), 0.0)

        c = Customer(shop_id=get_shop_id(), name=name, phone=phone, address=address)
        db.session.add(c)
        db.session.commit()

        if due_balance > 0:
            ts = int(datetime.now().timestamp())
            inv = Invoice(
                shop_id=get_shop_id(),
                customer_id=c.id,
                invoice_no=f"INV-DUE-{c.id}-{ts}",
                subtotal=due_balance,
                total_amount=due_balance,
                due_amount=due_balance,
                paid_amount=0.0,
                payment_status="Unpaid",
                payment_method="Credit",
                created_at=bangladesh_time()
            )
            db.session.add(inv)
            db.session.commit()

        return jsonify({'success': True, 'message': f"Customer '{name}' added successfully!", 'customer_id': c.id})

    @mobile_api_bp.route('/customers/collect-due', methods=['POST'])
    def mobile_collect_due():
        data = request.get_json(silent=True) or request.form
        customer_id = safe_int(data.get('customer_id'))
        amount = safe_float(data.get('amount'))

        c = Customer.query.get(customer_id)
        if not c or amount <= 0:
            return jsonify({'success': False, 'message': 'Invalid customer or collection amount'}), 400

        pay = CustomerPayment(
            shop_id=get_shop_id(),
            customer_id=c.id,
            amount=amount,
            payment_type="due_collection",
            method="Cash",
            note="Due Collection via Mobile POS",
            created_at=bangladesh_time()
        )
        db.session.add(pay)

        # Auto-allocate payment to customer's due invoices FIFO
        remaining = amount
        due_invoices = Invoice.query.filter(
            Invoice.shop_id == get_shop_id(),
            Invoice.customer_id == c.id,
            Invoice.due_amount > 0
        ).order_by(Invoice.created_at.asc()).all()

        for inv in due_invoices:
            if remaining <= 0:
                break
            to_pay = min(remaining, inv.due_amount)
            inv.paid_amount = (inv.paid_amount or 0) + to_pay
            inv.due_amount = max((inv.due_amount or 0) - to_pay, 0.0)
            inv.payment_status = "Paid" if inv.due_amount <= 0 else "Partial"
            remaining -= to_pay

        db.session.commit()

        return jsonify({
            'success': True,
            'message': f"Collected ৳{amount} from customer '{c.name}'!"
        })

    @mobile_api_bp.route('/suppliers', methods=['GET'])
    def mobile_suppliers():
        suppliers = Supplier.query.order_by(Supplier.name.asc()).all()
        return jsonify({
            'success': True,
            'suppliers': [{
                'id': s.id,
                'name': s.name,
                'phone': getattr(s, 'phone', '') or '',
                'company_name': getattr(s, 'company_name', '') or '',
                'due_balance': float(getattr(s, 'due_balance', 0.0) or 0.0)
            } for s in suppliers]
        })

    @mobile_api_bp.route('/suppliers/add', methods=['POST'])
    def mobile_add_supplier():
        data = request.get_json(silent=True) or request.form
        name = str(data.get('name') or '').strip()
        if not name:
            return jsonify({'success': False, 'message': 'Supplier name is required'}), 400

        phone = str(data.get('phone') or '').strip()
        company_name = str(data.get('company_name') or '').strip()
        due_balance = safe_float(data.get('due_balance'), 0.0)

        s = Supplier(shop_id=get_shop_id(), name=name, phone=phone, company_name=company_name, due_balance=due_balance)
        db.session.add(s)
        db.session.commit()

        return jsonify({'success': True, 'message': f"Supplier '{name}' added successfully!", 'supplier_id': s.id})

    @mobile_api_bp.route('/sell', methods=['POST'])
    def mobile_sell():
        data = request.get_json(silent=True) or request.form
        if not data:
            return jsonify({'success': False, 'message': 'Invalid JSON sale data'}), 400

        cart_items = data.get('items', [])
        if not cart_items:
            return jsonify({'success': False, 'message': 'Cart is empty'}), 400

        customer_id = safe_int(data.get('customer_id'))
        discount_amount = safe_float(data.get('discount_amount'), 0.0)
        paid_amount = safe_float(data.get('paid_amount'), 0.0)
        payment_method = str(data.get('payment_method') or 'Cash').strip()

        subtotal = 0.0
        sale_items_to_create = []

        for item in cart_items:
            pid = safe_int(item.get('product_id'))
            qty = safe_int(item.get('quantity'), 1)
            p = Product.query.get(pid)
            if not p:
                return jsonify({'success': False, 'message': f"Product ID {pid} not found"}), 400

            unit_price = safe_float(item.get('price'), getattr(p, 'sell_price', getattr(p, 'price', 0.0)))
            item_total = unit_price * qty
            subtotal += item_total

            # Stock check and update
            p.stock = max(0, (p.stock or 0) - qty)
            sale_items_to_create.append((p, qty, unit_price, item_total))

        grand_total = max(0.0, subtotal - discount_amount)
        due_amount = max(0.0, grand_total - paid_amount)

        now_bd = bangladesh_time()
        
        # Create Invoice using exact Invoice schema
        invoice_number = f"INV-{int(now_bd.timestamp())}"
        sale = Sale(
            shop_id=get_shop_id(),
            invoice_no=invoice_number,
            customer_id=customer_id if customer_id and customer_id > 0 else None,
            subtotal=subtotal,
            discount_amount=discount_amount,
            total_amount=grand_total,
            paid_amount=paid_amount,
            due_amount=due_amount,
            payment_method=payment_method,
            created_at=now_bd
        )
        db.session.add(sale)
        db.session.flush()

        for p, qty, unit_price, item_total in sale_items_to_create:
            si = SaleItem(
                invoice_id=sale.id,
                product_id=p.id,
                quantity=qty,
                price=unit_price,
                total=item_total
            )
            db.session.add(si)

        db.session.commit()

        return jsonify({
            'success': True,
            'message': f"Sale invoice #{sale.id} completed successfully!",
            'invoice_id': sale.id,
            'grand_total': grand_total,
            'paid_amount': paid_amount,
            'due_amount': due_amount
        })

    @mobile_api_bp.route('/sales', methods=['GET'])
    def mobile_sales():
        sales = Sale.query.order_by(Sale.id.desc()).limit(50).all()
        return jsonify({
            'success': True,
            'sales': [{
                'id': s.id,
                'invoice_no': getattr(s, 'invoice_no', f"INV-{s.id}"),
                'customer_name': s.customer.name if getattr(s, 'customer', None) else 'Guest Customer',
                'total_amount': float(getattr(s, 'total_amount', 0.0) or 0.0),
                'paid_amount': float(getattr(s, 'paid_amount', 0.0) or 0.0),
                'due_amount': float(getattr(s, 'due_amount', 0.0) or 0.0),
                'payment_method': getattr(s, 'payment_method', 'Cash') or 'Cash',
                'sale_date': getattr(s, 'created_at', None).strftime('%Y-%m-%d %H:%M') if getattr(s, 'created_at', None) else ''
            } for s in sales]
        })

    @mobile_api_bp.route('/expenses', methods=['GET'])
    def mobile_expenses():
        expenses = Expense.query.order_by(Expense.id.desc()).limit(50).all()
        return jsonify({
            'success': True,
            'expenses': [{
                'id': e.id,
                'title': getattr(e, 'title', getattr(e, 'category', 'Expense')) or 'Expense',
                'amount': float(getattr(e, 'amount', 0.0) or 0.0),
                'category': getattr(e, 'category', 'General') or 'General',
                'expense_date': getattr(e, 'created_at', None).strftime('%Y-%m-%d') if getattr(e, 'created_at', None) else ''
            } for e in expenses]
        })

    @mobile_api_bp.route('/expenses/add', methods=['POST'])
    def mobile_add_expense():
        data = request.get_json(silent=True) or request.form
        title = str(data.get('title') or data.get('category') or 'Expense').strip()
        amount = safe_float(data.get('amount'))

        if amount <= 0:
            return jsonify({'success': False, 'message': 'Expense amount must be greater than zero'}), 400

        e = Expense(
            shop_id=get_shop_id(),
            title=title,
            category=str(data.get('category') or 'General').strip(),
            amount=amount,
            created_at=bangladesh_time()
        )
        db.session.add(e)
        db.session.commit()

        return jsonify({'success': True, 'message': f"Expense ৳{amount} added successfully!"})

    @mobile_api_bp.route('/license', methods=['GET'])
    def mobile_license():
        shop = Shop.query.first()
        now_bd = bangladesh_time()
        days_left = max(0, (shop.license_expires_at.date() - now_bd.date()).days) if shop and shop.license_expires_at else 30

        return jsonify({
            'success': True,
            'shop_name': shop.shop_name if shop else 'Shop POS',
            'subscription_plan': shop.subscription_plan if shop else 'Free Trial',
            'license_expires_at': shop.license_expires_at.strftime('%Y-%m-%d') if shop and shop.license_expires_at else '',
            'days_left': days_left,
            'is_active': days_left > 0
        })

    app.register_blueprint(mobile_api_bp)
    print("[MOBILE REST API] Registered all /api/mobile/* Flutter endpoints successfully!")
