# api/serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
from inventory.models import Product, ProductCategory, InventoryTransaction, Supplier, PurchaseOrder
from sales.models import POSOrder, POSOrderItem, Customer
from accounts.models import AuditLog
from core.models import Branch
from subscriptions.models import PaymentTransaction as SubscriptionTransaction

User = get_user_model()


# ── Auth ──────────────────────────────────────────────────────────────────────

class LoginSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField(write_only=True)


class UserSerializer(serializers.ModelSerializer):
    role_display = serializers.CharField(source='get_role_display', read_only=True)
    branch_name  = serializers.CharField(source='branch.name', read_only=True, default=None)

    # ── Mobile app: company & plan context ─────────────────────────────────────
    company_id   = serializers.IntegerField(source='company.id', read_only=True, default=None)
    company_name = serializers.CharField(source='company.name', read_only=True, default='')
    company_slug = serializers.CharField(source='company.slug', read_only=True, default='')
    plan_name           = serializers.CharField(source='company.plan.name', read_only=True, default='Free')
    company_expiry_date = serializers.DateField(source='company.expiry_date', read_only=True, default=None)
    currency_symbol     = serializers.SerializerMethodField()
    vat_rate            = serializers.SerializerMethodField()
    feature_android_app  = serializers.BooleanField(source='company.plan.feature_android_app',  read_only=True, default=False)
    feature_profit_loss  = serializers.BooleanField(source='company.plan.feature_profit_loss',  read_only=True, default=False)
    feature_audit_logs   = serializers.BooleanField(source='company.plan.feature_audit_logs',   read_only=True, default=False)
    feature_credit_sales = serializers.BooleanField(source='company.plan.feature_credit_sales', read_only=True, default=True)
    feature_multi_branch = serializers.BooleanField(source='company.plan.feature_multi_branch', read_only=True, default=False)
    feature_advanced_reports = serializers.BooleanField(source='company.plan.feature_advanced_reports', read_only=True, default=False)

    def get_currency_symbol(self, obj):
        try:
            return obj.company.settings.currency_symbol
        except Exception:
            return '₦'

    def get_vat_rate(self, obj):
        try:
            return str(obj.company.settings.vat_rate)
        except Exception:
            return '0'

    class Meta:
        model  = User
        fields = ['id', 'username', 'first_name', 'last_name', 'email',
                  'role', 'role_display', 'branch', 'branch_name',
                  'is_active', 'date_joined',
                  'company_id', 'company_name', 'company_slug',
                  'plan_name', 'company_expiry_date', 'currency_symbol', 'vat_rate',
                  'feature_android_app', 'feature_profit_loss',
                  'feature_audit_logs', 'feature_credit_sales',
                  'feature_multi_branch', 'feature_advanced_reports']
        read_only_fields = ['id', 'date_joined']


class UserCreateSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    pin_raw  = serializers.CharField(write_only=True, required=False, allow_blank=True)

    class Meta:
        model  = User
        fields = ['username', 'first_name', 'last_name', 'email',
                  'password', 'role', 'branch', 'pin_raw']

    def create(self, validated_data):
        pin_raw = validated_data.pop('pin_raw', None)
        password = validated_data.pop('password')
        user = User(**validated_data)
        user.set_password(password)
        if pin_raw:
            user.set_pin(pin_raw)
        user.save()
        return user


# ── Branch ────────────────────────────────────────────────────────────────────

class BranchSerializer(serializers.ModelSerializer):
    class Meta:
        model  = Branch
        fields = ['id', 'name', 'code', 'address', 'phone', 'is_active', 'created_at']
        read_only_fields = ['id', 'created_at']


# ── Inventory ─────────────────────────────────────────────────────────────────

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model  = ProductCategory
        fields = ['id', 'name', 'description', 'created_at']
        read_only_fields = ['id', 'created_at']


class ProductSerializer(serializers.ModelSerializer):
    category_name = serializers.CharField(source='category.name', read_only=True)
    stock_status  = serializers.CharField(read_only=True)
    selling_price = serializers.DecimalField(source='price', max_digits=10, decimal_places=2, read_only=True)
    price         = serializers.DecimalField(max_digits=10, decimal_places=2, write_only=True)
    current_stock = serializers.IntegerField(source='stock_quantity', read_only=True)
    low_stock_threshold = serializers.IntegerField(source='minimum_stock', read_only=True)
    is_active = serializers.SerializerMethodField()

    class Meta:
        model  = Product
        fields = ['id', 'name', 'sku', 'barcode', 'description',
                  'category', 'category_name',
                  'selling_price', 'price', 'cost_price',
                  'current_stock', 'low_stock_threshold',
                  'stock_status', 'is_active',
                  'created_at']
        read_only_fields = ['id', 'stock_status', 'created_at']

    def get_is_active(self, obj):
        return obj.status == 'active'


class StockAdjustSerializer(serializers.Serializer):
    action      = serializers.ChoiceField(choices=['restock', 'reduce', 'adjust'])
    quantity    = serializers.IntegerField(min_value=0)
    note        = serializers.CharField(required=False, allow_blank=True)
    new_stock   = serializers.IntegerField(required=False, min_value=0)  # for adjust


class InventoryTransactionSerializer(serializers.ModelSerializer):
    product_name = serializers.CharField(source='product.name', read_only=True)

    class Meta:
        model  = InventoryTransaction
        fields = ['id', 'product', 'product_name', 'transaction_type',
                  'quantity', 'notes', 'created_at']
        read_only_fields = ['id', 'created_at']


class SupplierSerializer(serializers.ModelSerializer):
    class Meta:
        model  = Supplier
        fields = ['id', 'name', 'email', 'phone', 'address',
                  'total_purchases', 'outstanding_balance', 'created_at']
        read_only_fields = ['id', 'total_purchases', 'outstanding_balance', 'created_at']


class PurchaseOrderSerializer(serializers.ModelSerializer):
    supplier_name = serializers.CharField(source='supplier.name', read_only=True)

    class Meta:
        model  = PurchaseOrder
        fields = ['id', 'supplier', 'supplier_name', 'status',
                  'total_amount', 'notes', 'created_at', 'received_at']
        read_only_fields = ['id', 'created_at', 'received_at']


# ── Sales ─────────────────────────────────────────────────────────────────────

class OrderItemSerializer(serializers.ModelSerializer):
    # Use snapshot name with fallback to FK product name
    product_name = serializers.SerializerMethodField()

    class Meta:
        model  = POSOrderItem
        fields = ['id', 'product', 'product_name', 'quantity',
                  'unit_price', 'total_price']
        read_only_fields = ['id', 'total_price']

    def get_product_name(self, obj):
        # Prefer the snapshot name stored at sale time
        if obj.product_name:
            return obj.product_name
        if obj.product:
            return obj.product.name
        return 'Deleted product'


class OrderItemCreateSerializer(serializers.Serializer):
    product_id = serializers.IntegerField()
    quantity   = serializers.IntegerField(min_value=1)
    discount   = serializers.DecimalField(max_digits=5, decimal_places=2, default=0)


class OrderSerializer(serializers.ModelSerializer):
    # related_name on POSOrderItem.order is 'items' — NOT 'posorderitem_set'
    items = OrderItemSerializer(many=True, read_only=True)

    class Meta:
        model  = POSOrder
        fields = ['id', 'order_number', 'cashier',
                  'customer_name', 'customer_phone',
                  'payment_method', 'amount_paid', 'final_amount',
                  'discount_amount', 'total_amount',
                  'payment_status', 'balance_amount', 'status', 'branch',
                  'items', 'created_at']
        read_only_fields = ['id', 'order_number', 'payment_status',
                            'balance_amount', 'status', 'created_at']



class OrderCreateSerializer(serializers.Serializer):
    client_id      = serializers.CharField(required=False, allow_blank=True)
    customer_name  = serializers.CharField(required=False, allow_blank=True)
    customer_phone = serializers.CharField(required=False, allow_blank=True)
    payment_method = serializers.ChoiceField(
        choices=['cash', 'transfer', 'pos', 'mobile_money', 'credit'],
        default='cash'
    )
    amount_paid    = serializers.DecimalField(max_digits=10, decimal_places=2, default=0)
    discount       = serializers.DecimalField(max_digits=5, decimal_places=2, default=0)
    branch         = serializers.IntegerField(required=False)
    items          = OrderItemCreateSerializer(many=True)


class CustomerSerializer(serializers.ModelSerializer):
    total_orders      = serializers.IntegerField(read_only=True)
    total_spent       = serializers.DecimalField(max_digits=15, decimal_places=2, read_only=True)
    outstanding_balance = serializers.DecimalField(max_digits=15, decimal_places=2, read_only=True)

    class Meta:
        model  = Customer
        fields = ['id', 'name', 'phone', 'email', 'address', 'notes',
                  'total_orders', 'total_spent', 'outstanding_balance', 'created_at']
        read_only_fields = ['id', 'created_at']


# ── Audit Log ─────────────────────────────────────────────────────────────────

class AuditLogSerializer(serializers.ModelSerializer):
    user_name = serializers.CharField(source='user.username', read_only=True)

    class Meta:
        model  = AuditLog
        fields = ['id', 'user', 'user_name', 'action', 'target',
                  'ip_address', 'timestamp']
        read_only_fields = ['id', 'timestamp']


# ── Dashboard / P&L ───────────────────────────────────────────────────────────

class DashboardSerializer(serializers.Serializer):
    today_sales        = serializers.DecimalField(max_digits=15, decimal_places=2)
    today_transactions = serializers.IntegerField()
    today_customers    = serializers.IntegerField()
    avg_order_value    = serializers.DecimalField(max_digits=15, decimal_places=2)
    low_stock_products = serializers.IntegerField()
    total_users        = serializers.IntegerField()


class PnLSerializer(serializers.Serializer):
    date_from          = serializers.DateField()
    date_to            = serializers.DateField()
    total_revenue      = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_cost         = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_profit       = serializers.DecimalField(max_digits=15, decimal_places=2)
    credit_outstanding = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_orders_count = serializers.IntegerField()


# ── Monnify / Subscriptions ───────────────────────────────────────────────────

class SubscriptionTransactionSerializer(serializers.ModelSerializer):
    company_name = serializers.CharField(source='company.name', read_only=True)
    plan_name    = serializers.CharField(source='plan.name', read_only=True)

    class Meta:
        model  = SubscriptionTransaction
        fields = ['id', 'company', 'company_name', 'plan', 'plan_name', 
                  'amount', 'payment_reference', 'monnify_reference', 'status', 
                  'paid_at', 'created_at']
        read_only_fields = ['id', 'created_at']


# ── Subscription Status (Mobile) ──────────────────────────────────────────────

class PlanListSerializer(serializers.Serializer):
    """Public plan listing for the mobile upgrade/pricing screen."""
    id              = serializers.IntegerField()
    name            = serializers.CharField()
    price_monthly   = serializers.DecimalField(max_digits=10, decimal_places=2)
    price_bimonthly = serializers.DecimalField(max_digits=10, decimal_places=2)
    price_trimonthly = serializers.DecimalField(max_digits=10, decimal_places=2)
    price_yearly    = serializers.DecimalField(max_digits=10, decimal_places=2)
    max_products    = serializers.IntegerField()
    max_staff       = serializers.IntegerField()
    max_branches    = serializers.IntegerField()
    max_orders_per_day = serializers.IntegerField()
    # Feature flags
    feature_android_app      = serializers.BooleanField()
    feature_profit_loss      = serializers.BooleanField()
    feature_audit_logs       = serializers.BooleanField()
    feature_credit_sales     = serializers.BooleanField()
    feature_multi_branch     = serializers.BooleanField()
    feature_advanced_reports = serializers.BooleanField()
    feature_barcode_pos      = serializers.BooleanField()
    feature_promo            = serializers.BooleanField()
    feature_discount         = serializers.BooleanField()
    feature_export           = serializers.BooleanField()
    display_order            = serializers.IntegerField()


class SubscriptionStatusSerializer(serializers.Serializer):
    """Full subscription status snapshot for the mobile app."""
    # Subscription fields
    is_trial        = serializers.BooleanField()
    is_active       = serializers.BooleanField()
    is_expired      = serializers.BooleanField()
    payment_status  = serializers.CharField()
    billing_cycle   = serializers.CharField()
    start_date      = serializers.DateField()
    expiry_date     = serializers.DateField(allow_null=True)
    days_remaining  = serializers.IntegerField(allow_null=True)
    # Plan summary
    plan_id         = serializers.IntegerField()
    plan_name       = serializers.CharField()
    plan_price_monthly = serializers.DecimalField(max_digits=10, decimal_places=2)
    # Pending downgrade
    pending_downgrade_plan = serializers.CharField(allow_null=True)
    # Recent transactions
    recent_transactions = SubscriptionTransactionSerializer(many=True)


class SaasPromoValidateSerializer(serializers.Serializer):
    """Validate a SaaS subscription promo code from the mobile app."""
    code         = serializers.CharField(max_length=50)
    plan_id      = serializers.IntegerField()
    billing_cycle = serializers.ChoiceField(
        choices=['monthly', 'bimonthly', 'trimonthly', 'yearly'],
        default='monthly'
    )


# ── Profile ───────────────────────────────────────────────────────────────────

class ProfileUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model  = User
        fields = ['first_name', 'last_name', 'email', 'phone']

    def update(self, instance, validated_data):
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        return instance


class ChangePinSerializer(serializers.Serializer):
    current_pin = serializers.CharField(write_only=True, required=False, allow_blank=True,
                                        help_text="Required if user already has a PIN set.")
    new_pin     = serializers.CharField(write_only=True, min_length=4, max_length=8)

    def validate_new_pin(self, value):
        if not value.isdigit():
            raise serializers.ValidationError("PIN must contain digits only.")
        return value


# ── Notifications ─────────────────────────────────────────────────────────────

class NotificationSerializer(serializers.ModelSerializer):
    class Meta:
        model  = None  # set dynamically in view to avoid circular import
        fields = ['id', 'title', 'message', 'notification_type', 'icon',
                  'is_read', 'url', 'created_at']
        read_only_fields = ['id', 'created_at']


# ── Expenses ──────────────────────────────────────────────────────────────────

class ExpenseCategorySerializer(serializers.Serializer):
    id   = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=100)


class ExpenseSerializer(serializers.Serializer):
    """Operating expense read/write serializer for the mobile app."""
    id              = serializers.IntegerField(read_only=True)
    category        = serializers.IntegerField(source='category_id', allow_null=True, required=False)
    category_name   = serializers.SerializerMethodField()
    amount          = serializers.DecimalField(max_digits=12, decimal_places=2)
    expense_date    = serializers.DateField()
    reference       = serializers.CharField(max_length=100, allow_blank=True, required=False)
    notes           = serializers.CharField(allow_blank=True, required=False)
    logged_by_name  = serializers.SerializerMethodField()
    created_at      = serializers.DateTimeField(read_only=True)

    def get_category_name(self, obj):
        return obj.category.name if obj.category else 'Uncategorized'

    def get_logged_by_name(self, obj):
        if obj.logged_by:
            return obj.logged_by.get_full_name() or obj.logged_by.username
        return ''


# ── Bulk Offline Sync ─────────────────────────────────────────────────────────

class BulkOrderSyncSerializer(serializers.Serializer):
    """Wraps a list of OrderCreateSerializer payloads for bulk offline sync."""
    orders = OrderCreateSerializer(many=True)


class BulkSyncResultSerializer(serializers.Serializer):
    """Per-order result returned after a bulk sync push."""
    client_id = serializers.CharField()
    status    = serializers.ChoiceField(choices=['created', 'duplicate', 'error'])
    order_id  = serializers.IntegerField(allow_null=True)
    order_number = serializers.CharField(allow_null=True)
    detail    = serializers.CharField(allow_blank=True)
