from django import forms
from .models import (
    Asset,
    AssetAssignment,
    AssetMaintenance,
    Branch,
    Category,
    Product,
    ProductBatch,
    PurchaseReturn,
    PurchaseReturnItem,
    PurchaseOrder,
    PurchaseOrderItem,
    StockAdjustmentRequest,
    StockLocation,
    StockMovement,
    StockTransfer,
    StockTransferItem,
    Supplier,
    UserStoreAssignment,
)
from finance.models import Account
from core.permissions import Capability


class CategoryForm(forms.ModelForm):
    class Meta:
        model = Category
        fields = ['name', 'description']


class BranchForm(forms.ModelForm):
    class Meta:
        model = Branch
        fields = ['name', 'code', 'location', 'contact_phone', 'is_active']


def _storekeeper_branch(user):
    if not user or not getattr(user, "is_authenticated", False):
        return None
    if not getattr(user, "is_storekeeper", False):
        return None
    assignment = (
        UserStoreAssignment.objects.select_related("location__branch")
        .filter(user=user, is_active=True)
        .first()
    )
    if not assignment or not assignment.location_id:
        return None
    return assignment.location.branch


class ProductForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = [
            'category', 'name', 'sku', 'barcode', 'unit',
            'cost_price', 'selling_price',
            'stock_quantity', 'low_stock_alert', 'overstock_alert',
            'track_expiry', 'track_serial', 'image',
        ]
        help_texts = {
            'sku': 'Optional. Barcode or product code.',
            'barcode': 'Scan code used by barcode readers.',
            'low_stock_alert': 'Get alerted when stock falls to this level.',
            'overstock_alert': 'Optional. Alert when stock reaches/exceeds this level.',
            'stock_quantity': 'Opening stock quantity.',
            'track_expiry': 'Enable if this product has expiry dates.',
            'track_serial': 'Enable if each unit must have a serial number.',
        }

    def __init__(self, *args, user=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.user = user
        can_edit_price = bool(
            user and getattr(user, "is_authenticated", False)
            and user.has_capability(Capability.INVENTORY_PRICE_UPDATE)
        )
        if not can_edit_price:
            self.fields['cost_price'].disabled = True
            self.fields['selling_price'].disabled = True
            self.fields['cost_price'].help_text = (
                "Price editing requires manager-level approval."
            )
            self.fields['selling_price'].help_text = (
                "Price editing requires manager-level approval."
            )

    def clean_cost_price(self):
        value = self.cleaned_data.get('cost_price')
        if not self.user or self.user.has_capability(Capability.INVENTORY_PRICE_UPDATE):
            return value
        return self.instance.cost_price if self.instance.pk else 0

    def clean_selling_price(self):
        value = self.cleaned_data.get('selling_price')
        if not self.user or self.user.has_capability(Capability.INVENTORY_PRICE_UPDATE):
            return value
        return self.instance.selling_price if self.instance.pk else 0


class StockAdjustmentForm(forms.Form):
    quantity = forms.DecimalField(max_digits=15, decimal_places=2)
    movement_type = forms.ChoiceField(choices=[
        ('stock_in', 'Add Stock'),
        ('adjustment', 'Adjustment'),
        ('return', 'Return'),
    ])
    note = forms.CharField(required=False, widget=forms.Textarea(attrs={'rows': 2}))


class SupplierForm(forms.ModelForm):
    class Meta:
        model = Supplier
        fields = ['name', 'phone', 'email', 'address', 'note']
        widgets = {
            'address': forms.Textarea(attrs={'rows': 2}),
            'note': forms.Textarea(attrs={'rows': 2}),
        }


class PurchaseOrderForm(forms.ModelForm):
    class Meta:
        model = PurchaseOrder
        fields = [
            'supplier', 'supplier_invoice_number',
            'date', 'due_date',
            'account', 'amount_paid', 'note'
        ]
        widgets = {
            'date': forms.DateInput(attrs={'type': 'date'}),
            'due_date': forms.DateInput(attrs={'type': 'date'}),
            'note': forms.Textarea(attrs={'rows': 2}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['account'].queryset = Account.objects.filter(is_active=True)
        self.fields['account'].required = False
        self.fields['supplier'].queryset = Supplier.objects.filter(is_active=True)


class PurchaseOrderItemForm(forms.ModelForm):
    class Meta:
        model = PurchaseOrderItem
        fields = ['product', 'quantity', 'unit_cost']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['product'].queryset = Product.objects.filter(is_active=True)


PurchaseOrderItemFormSet = forms.inlineformset_factory(
    PurchaseOrder, PurchaseOrderItem,
    form=PurchaseOrderItemForm,
    extra=3,
    min_num=1,
    validate_min=True,
    can_delete=True,
)


class PurchaseReturnForm(forms.ModelForm):
    class Meta:
        model = PurchaseReturn
        fields = ['purchase_order', 'date', 'reason']
        widgets = {
            'date': forms.DateInput(attrs={'type': 'date'}),
            'reason': forms.Textarea(attrs={'rows': 2}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['purchase_order'].queryset = PurchaseOrder.objects.filter(
            status=PurchaseOrder.Status.RECEIVED
        )


class PurchaseReturnItemForm(forms.ModelForm):
    class Meta:
        model = PurchaseReturnItem
        fields = ['product', 'quantity', 'unit_cost']


PurchaseReturnItemFormSet = forms.inlineformset_factory(
    PurchaseReturn,
    PurchaseReturnItem,
    form=PurchaseReturnItemForm,
    extra=2,
    min_num=1,
    validate_min=True,
    can_delete=True,
)


class StockLocationForm(forms.ModelForm):
    class Meta:
        model = StockLocation
        fields = ['branch', 'name', 'code', 'description', 'is_active']
        widgets = {
            'description': forms.Textarea(attrs={'rows': 2}),
        }

    def __init__(self, *args, user=None, branch_scope=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.user = user
        self.branch_scope = branch_scope or _storekeeper_branch(user)
        branches = Branch.objects.filter(is_active=True).order_by('name')
        if self.branch_scope:
            branches = branches.filter(pk=self.branch_scope.pk)
            self.initial.setdefault('branch', self.branch_scope.pk)
        self.fields['branch'].queryset = branches
        if self.branch_scope and user and user.is_storekeeper:
            self.fields['branch'].disabled = True

    def clean(self):
        cleaned_data = super().clean()
        if self.user and self.user.is_storekeeper and not self.branch_scope:
            raise forms.ValidationError(
                'No active store assignment found for your user. Contact administrator.'
            )
        if self.branch_scope:
            cleaned_data['branch'] = self.branch_scope
        return cleaned_data


class ProductBatchForm(forms.ModelForm):
    class Meta:
        model = ProductBatch
        fields = ['product', 'location', 'batch_number', 'expiry_date', 'quantity', 'unit_cost']
        widgets = {
            'expiry_date': forms.DateInput(attrs={'type': 'date'}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['product'].queryset = Product.objects.filter(is_active=True)
        self.fields['location'].queryset = StockLocation.objects.filter(is_active=True)


class StockTransferForm(forms.ModelForm):
    branch = forms.ModelChoiceField(
        queryset=Branch.objects.none(),
        required=False,
        empty_label='All Branches',
        help_text='Optional. Pick a branch to limit source/destination locations.',
    )

    class Meta:
        model = StockTransfer
        fields = ['from_location', 'to_location', 'note']
        widgets = {
            'note': forms.Textarea(attrs={'rows': 2}),
        }

    def __init__(self, *args, user=None, branch_scope=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.user = user
        self.branch_scope = branch_scope or _storekeeper_branch(user)

        branches = Branch.objects.filter(is_active=True).order_by('name')
        if self.branch_scope:
            branches = branches.filter(pk=self.branch_scope.pk)
        self.fields['branch'].queryset = branches
        if self.branch_scope:
            self.initial.setdefault('branch', self.branch_scope.pk)
            if user and user.is_storekeeper:
                self.fields['branch'].disabled = True

        selected_branch = None
        if self.branch_scope:
            selected_branch = self.branch_scope
        else:
            branch_value = self.data.get('branch') if self.is_bound else self.initial.get('branch')
            if branch_value:
                selected_branch = branches.filter(pk=branch_value).first()

        locations = StockLocation.objects.filter(is_active=True).select_related('branch')
        if selected_branch:
            locations = locations.filter(branch=selected_branch)
        self.fields['from_location'].queryset = locations
        self.fields['to_location'].queryset = locations

    def clean(self):
        cleaned_data = super().clean()
        from_location = cleaned_data.get('from_location')
        to_location = cleaned_data.get('to_location')
        branch = cleaned_data.get('branch')

        if self.user and self.user.is_storekeeper and not self.branch_scope:
            raise forms.ValidationError(
                'No active store assignment found for your user. Contact administrator.'
            )

        if from_location == to_location:
            raise forms.ValidationError('Source and destination locations must differ.')

        if self.branch_scope:
            cleaned_data['branch'] = self.branch_scope
            if from_location and from_location.branch_id != self.branch_scope.id:
                self.add_error('from_location', 'Source location must belong to your assigned branch.')
            if to_location and to_location.branch_id != self.branch_scope.id:
                self.add_error('to_location', 'Destination location must belong to your assigned branch.')
            return cleaned_data

        if branch:
            if from_location and from_location.branch_id != branch.id:
                self.add_error('from_location', 'Source location must belong to selected branch.')
            if to_location and to_location.branch_id != branch.id:
                self.add_error('to_location', 'Destination location must belong to selected branch.')
        return cleaned_data


class StockTransferItemForm(forms.ModelForm):
    class Meta:
        model = StockTransferItem
        fields = ['product', 'quantity', 'batch', 'serial']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['product'].queryset = Product.objects.filter(is_active=True)
        self.fields['batch'].required = False
        self.fields['serial'].required = False


StockTransferItemFormSet = forms.inlineformset_factory(
    StockTransfer,
    StockTransferItem,
    form=StockTransferItemForm,
    extra=3,
    min_num=1,
    validate_min=True,
    can_delete=True,
)


class StockAdjustmentRequestForm(forms.ModelForm):
    branch = forms.ModelChoiceField(
        queryset=Branch.objects.none(),
        required=False,
        empty_label='All Branches',
        help_text='Optional. Pick a branch to narrow locations.',
    )

    class Meta:
        model = StockAdjustmentRequest
        fields = ['product', 'location', 'quantity', 'reason', 'note']
        widgets = {
            'note': forms.Textarea(attrs={'rows': 2}),
        }

    def __init__(self, *args, user=None, branch_scope=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.user = user
        self.branch_scope = branch_scope or _storekeeper_branch(user)

        self.fields['product'].queryset = Product.objects.filter(is_active=True)
        branches = Branch.objects.filter(is_active=True).order_by('name')
        if self.branch_scope:
            branches = branches.filter(pk=self.branch_scope.pk)
        self.fields['branch'].queryset = branches
        if self.branch_scope:
            self.initial.setdefault('branch', self.branch_scope.pk)
            if user and user.is_storekeeper:
                self.fields['branch'].disabled = True

        selected_branch = None
        if self.branch_scope:
            selected_branch = self.branch_scope
        else:
            branch_value = self.data.get('branch') if self.is_bound else self.initial.get('branch')
            if branch_value:
                selected_branch = branches.filter(pk=branch_value).first()

        locations = StockLocation.objects.filter(is_active=True).select_related('branch')
        if selected_branch:
            locations = locations.filter(branch=selected_branch)
        self.fields['location'].queryset = locations
        self.fields['location'].required = True

    def clean(self):
        cleaned_data = super().clean()
        branch = cleaned_data.get('branch')
        location = cleaned_data.get('location')

        if self.user and self.user.is_storekeeper and not self.branch_scope:
            raise forms.ValidationError(
                'No active store assignment found for your user. Contact administrator.'
            )

        if self.branch_scope:
            cleaned_data['branch'] = self.branch_scope
            if location and location.branch_id != self.branch_scope.id:
                self.add_error('location', 'Selected location must belong to your assigned branch.')
            return cleaned_data

        if branch and location and location.branch_id != branch.id:
            self.add_error('location', 'Selected location must belong to selected branch.')
        return cleaned_data


class AssetForm(forms.ModelForm):
    class Meta:
        model = Asset
        fields = [
            'name', 'code', 'category', 'serial_number', 'location',
            'purchase_date', 'purchase_cost', 'useful_life_years',
            'salvage_value', 'status', 'note',
        ]
        widgets = {
            'purchase_date': forms.DateInput(attrs={'type': 'date'}),
            'note': forms.Textarea(attrs={'rows': 2}),
        }

    def __init__(self, *args, user=None, branch_scope=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.user = user
        self.branch_scope = branch_scope or _storekeeper_branch(user)

        locations = StockLocation.objects.filter(is_active=True).order_by('name')
        if self.branch_scope:
            locations = locations.filter(branch=self.branch_scope)
        self.fields['location'].queryset = locations

    def clean(self):
        cleaned_data = super().clean()
        location = cleaned_data.get('location')

        if self.user and self.user.is_storekeeper and not self.branch_scope:
            raise forms.ValidationError(
                'No active store assignment found for your user. Contact administrator.'
            )

        if self.user and self.user.is_storekeeper and self.branch_scope and not location:
            self.add_error('location', 'Location is required for your assigned branch.')
            return cleaned_data

        if self.branch_scope and location and location.branch_id != self.branch_scope.id:
            self.add_error('location', 'Selected location must belong to your assigned branch.')

        return cleaned_data


class AssetAssignmentForm(forms.ModelForm):
    class Meta:
        model = AssetAssignment
        fields = ['asset', 'assigned_to', 'assigned_date', 'returned_date', 'note']
        widgets = {
            'assigned_date': forms.DateInput(attrs={'type': 'date'}),
            'returned_date': forms.DateInput(attrs={'type': 'date'}),
            'note': forms.Textarea(attrs={'rows': 2}),
        }


class AssetMaintenanceForm(forms.ModelForm):
    class Meta:
        model = AssetMaintenance
        fields = ['asset', 'description', 'cost', 'service_date', 'next_due_date', 'performed_by', 'note']
        widgets = {
            'service_date': forms.DateInput(attrs={'type': 'date'}),
            'next_due_date': forms.DateInput(attrs={'type': 'date'}),
            'note': forms.Textarea(attrs={'rows': 2}),
        }
