from django.db import transaction
from django.contrib.auth.decorators import login_required
import json
from django.views.decorators.csrf import csrf_exempt

from django.shortcuts import render, get_object_or_404, redirect
from django.views import View
from django.http import JsonResponse
from django.urls import reverse_lazy
from django.utils.html import escape
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.core.paginator import Paginator
from django.db.models import Q  

from django.views.generic import ListView, CreateView, UpdateView, DeleteView

from accountant.models import ExpenseItem
from .models import MedicinePack, MedicinePackItem,WarehouseItem, WarehouseItemHistory, Category
from .forms import WarehouseItemForm, CategoryForm
from core.models import Service
from reservation.models import Reservation,ReservationWarehouse
@login_required
def get_packs_for_reservation(request, reservation_id):
    try:
        reservation = Reservation.objects.get(id=reservation_id)
        print("in get_packs_for_reservation")
        # packs = MedicinePack.objects.filter(service=reservation.service)
        packs = MedicinePack.objects.all()

        pack_list = []
        for p in packs:
            medician_items = MedicinePackItem.objects.filter(pack=p)
            items = []
            for medician_item in medician_items:
                items.append({'name':medician_item.medicine.name,'quantity':medician_item.quantity})
            pack_list.append({'id': p.id, 'name': p.name, 'total_value': float(p.total_value),'service_name':p.service.name, 'items':items})

        return JsonResponse({'success': True, 'packs': pack_list})
    except Reservation.DoesNotExist:
        return JsonResponse({'success': False, 'message': 'No found'})


@csrf_exempt
@login_required
def apply_pack_to_reservation(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        pack_id = data.get('pack_id')
        reservation_id = data.get('reservation_id')
        quantity = int(data.get('quantity', 1))  # دریافت تعداد با مقدار پیش‌فرض 1

        try:
            pack = MedicinePack.objects.select_related().prefetch_related('items__medicine').get(id=pack_id)
            reservation = Reservation.objects.get(id=reservation_id)
            record = reservation.medical_record

            insufficient_items = []
            # بررسی موجودی انبار با در نظر گرفتن تعداد درخواستی
            for item in pack.items.all():
                required_quantity = item.quantity * quantity  # محاسبه تعداد مورد نیاز با ضرب در تعداد پک
                if item.medicine.quantity < required_quantity:
                    insufficient_items.append({
                        'name': item.medicine.name,
                        'required': required_quantity,
                        'available': item.medicine.quantity
                    })

            if insufficient_items:
                return JsonResponse({
                    'success': False,
                    'type': 'stock_error',
                    'message': 'There is not enough stock of some items.',
                    'items': insufficient_items
                })

            # کاهش موجودی انبار و ذخیره در نسخه پزشکی
            meds_text = ""
            for item in pack.items.all():
                total_quantity = item.quantity * quantity

                # ایجاد رکورد برای هر آیتم
                reserv_medical = ReservationWarehouse.objects.create(
                    reservation=reservation,
                    category=item.medicine.category,
                    name=item.medicine.name,
                    quantity=total_quantity,
                    price=item.unit_price * total_quantity,  # محاسبه قیمت کل
                    description=f"From pack: {pack.name} (x{quantity})"
                )

                # کاهش موجودی انبار
                medicine = item.medicine
                medicine.quantity -= total_quantity
                medicine.updated_by = request.user
                medicine.save()

                meds_text += f"{medicine.name} × {total_quantity}\n"

            # به‌روزرسانی نسخه پزشکی
            record.prescriptions = (record.prescriptions or "") + meds_text
            record.save()

            return JsonResponse({
                'success': True,
                'message': f'Successfully added {quantity} pack(s) to reservation.'
            })

        except Exception as e:
            return JsonResponse({'success': False, 'message': str(e)})

    return JsonResponse({'success': False, 'message': 'Invalid method'})

@csrf_exempt
@login_required
def add_item_to_reservation(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        item_id = data.get('item_id')
        reservation_id = data.get('reservation_id')
        quantity = int(data.get('quantity'))

        try:
            item = WarehouseItem.objects.get(id=item_id)
            if item.quantity < quantity:
                return JsonResponse({
                    'success': False,
                    'message': f'There is not enough creature for "{item.name}".'
                })

            reservation = Reservation.objects.get(id=reservation_id)

            # کم کردن از انبار
            item.quantity -= quantity
            item.save()

            ReservationWarehouse.objects.create(
                reservation=reservation,
                category=item.category,
                name=item.name,
                quantity=quantity,
                price=item.unit_price * quantity,
                description=f"Drug use {item.name}"
            )

            return JsonResponse({'success': True})

        except Exception as e:
            return JsonResponse({'success': False, 'message': str(e)})
@login_required
def get_available_items(request):
    items = WarehouseItem.objects.filter(quantity__gt=0).select_related('category')
    data = [{
        'id': item.id,
        'name': item.name,
        'quantity': item.quantity,
        'unit_price': str(item.unit_price),
        'category': item.category.name if item.category else '-'
    } for item in items]
    return JsonResponse({'items': data})

@login_required
def medicine_pack_list(request):
    """لیست پک‌های دارویی"""
    packs = MedicinePack.objects.all()

    # جستجو
    search_query = request.GET.get('search', '')
    if search_query:
        packs = packs.filter(name__icontains=search_query)

    # صفحه‌بندی
    paginator = Paginator(packs, 10)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'page_obj': page_obj,
        'search_query': search_query,
    }
    return render(request, 'warehouse/medicine_pack_list.html', context)


@login_required
@csrf_exempt
def get_pack_by_service(request):
    """بررسی وجود پک برای سرویس انتخاب‌شده"""
    if request.method == 'POST':
        service_id = request.POST.get('service_id')
        try:
            pack = MedicinePack.objects.get(service_id=service_id)
            medicine_pack_item = MedicinePackItem.objects.filter(pack=pack)
            items=[]
            for item in medicine_pack_item:
                medician = {}
                medician['name'] = item.medicine.name
                medician['quantity'] = item.quantity
                items.append(medician)
            return JsonResponse({
                'exists': True,
                'pack_name': pack.name,
                'items':items
            })
        except MedicinePack.DoesNotExist:
            return JsonResponse({'exists': False})

    return JsonResponse({'error': 'Invalid request'}, status=400)

@login_required
def create_medicine_pack(request):
    print("in create medicine_pack")
    print("request.POST=",request.POST)
    """ایجاد یا ویرایش پک دارویی برای یک سرویس"""
    try:
        if request.method == 'POST':
            service_id = request.POST.get('service_id')
            pack_name = request.POST.get('pack_name')
            pack_description = request.POST.get('pack_description', '')
            selected_medicines = request.POST.getlist('medicines')
            quantities = request.POST.getlist('quantities')

            service = get_object_or_404(Service, id=service_id)

            if not selected_medicines:
                messages.error(request, 'Select at least one medicine.')
                return redirect('warehouse:create_medicine_pack')

            try:
                with transaction.atomic():
                    # پیدا کردن یا ساخت پک برای سرویس
                    pack, created = MedicinePack.objects.get_or_create(
                        service=service,
                        defaults={
                            'name': pack_name,
                            'description': pack_description,
                            'created_by': request.user
                        }
                    )
                    if not created:
                        # اگر پک از قبل وجود دارد، اقلام قبلی را حذف کرده و داروها را به انبار بازگردان
                        # for item in pack.items.all():
                        #     item.medicine.quantity += item.quantity
                        #     item.medicine.updated_by = request.user
                        #     item.medicine.save()
                        pack.items.all().delete()

                    # اضافه کردن داروهای جدید
                    for i, medicine_id in enumerate(selected_medicines):
                        # if i < len(quantities) and quantities[i]:
                        quantity = int(quantities[i])
                        medicine = get_object_or_404(WarehouseItem, id=medicine_id)

                        # if medicine.quantity < quantity:
                        #     raise ValueError(f' {medicine.name}  not avaiable')
                        #
                        # medicine.quantity -= quantity
                        # medicine.updated_by = request.user
                        # medicine.save()

                        MedicinePackItem.objects.create(
                            pack=pack,
                            medicine=medicine,
                            quantity=quantity,
                            unit_price=medicine.unit_price
                        )

                    pack.calculate_total_value()

                    messages.success(request, f'Pack save for "{service}".')
                    return redirect('warehouse:medicine_pack_detail', pack_id=pack.id)

            except ValueError as e:
                messages.error(request, str(e))
            except Exception as e:
                messages.error(request, 'Error.'+str(e))

        # medicines = WarehouseItem.objects.filter(quantity__gt=0).order_by('name')
        medicines = WarehouseItem.objects.all().order_by('name')
        services = Service.objects.all()

        context = {
            'medicines': medicines,
            'services': services,
        }
        return render(request, 'warehouse/create_medicine_pack.html', context)
    except Exception as e:
        print(e)
        return render(request, 'warehouse/create_medicine_pack.html', {})


@login_required
def edit_medicine_pack(request, pack_id):
    """ویرایش پک دارویی با حفظ داروهای موجود"""
    pack = get_object_or_404(MedicinePack, id=pack_id)
    current_items = pack.items.select_related('medicine').all()

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # دریافت داده‌های فرم
                pack.name = request.POST.get('pack_name', pack.name)
                pack.description = request.POST.get('pack_description', pack.description)
                service_id = request.POST.get('service_id')
                if service_id:
                    pack.service = get_object_or_404(Service, id=service_id)
                pack.save()

                # پردازش داروهای ارسال شده
                medicine_ids = request.POST.getlist('medicines')
                quantities = request.POST.getlist('quantities')

                # ایجاد دیکشنری از داروهای جدید
                new_items = {}
                for i, medicine_id in enumerate(medicine_ids):
                    new_items[int(medicine_id)] = int(quantities[i])

                # به‌روزرسانی یا حذف داروهای موجود
                for item in current_items:
                    if item.medicine.id in new_items:
                        # به‌روزرسانی تعداد
                        item.quantity = new_items[item.medicine.id]
                        item.save()
                        del new_items[item.medicine.id]
                    else:
                        # حذف دارویی که در فرم جدید وجود ندارد
                        item.delete()

                # اضافه کردن داروهای جدید
                for medicine_id, quantity in new_items.items():
                    medicine = get_object_or_404(WarehouseItem, id=medicine_id)
                    MedicinePackItem.objects.create(
                        pack=pack,
                        medicine=medicine,
                        quantity=quantity,
                        unit_price=medicine.unit_price
                    )

                pack.calculate_total_value()
                messages.success(request, 'Pack updated successfully.')
                return redirect('warehouse:medicine_pack_detail', pack_id=pack.id)

        except Exception as e:
            messages.error(request, f'Error updating pack: {str(e)}')

    # آماده کردن داده‌ها برای نمایش در فرم
    medicines = WarehouseItem.objects.all().order_by('name')
    services = Service.objects.all()

    context = {
        'pack': pack,
        'medicines': medicines,
        'services': services,
        'current_items': current_items,
        'editing': True
    }

    return render(request, 'warehouse/create_medicine_pack.html', context)
@login_required
def medicine_pack_detail(request, pack_id):
    """جزئیات پک دارویی"""
    pack = get_object_or_404(MedicinePack, id=pack_id)
    pack_items = pack.items.select_related('medicine').all()

    context = {
        'pack': pack,
        'pack_items': pack_items,
    }
    return render(request, 'warehouse/medicine_pack_detail.html', context)

@login_required
def delete_medicine_pack(request, pack_id):
    """حذف پک دارویی"""
    pack = get_object_or_404(MedicinePack, id=pack_id)

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # برگرداندن داروها به انبار
                for item in pack.items.all():
                    medicine = item.medicine
                    medicine.quantity += item.quantity
                    medicine.updated_by = request.user
                    medicine.save()

                pack_name = pack.name
                pack.delete()

                messages.success(request, f'pack medician of  "{pack_name}" It was removed and the drugs were returned to storage.')
                return redirect('warehouse:medicine_pack_list')

        except Exception as e:
            messages.error(request, 'Error deleting medicine pack.')

    return redirect('warehouse:medicine_pack_detail', pack_id=pack_id)


@csrf_exempt
@login_required
def get_medicine_info(request):
    """دریافت اطلاعات دارو برای AJAX"""
    if request.method == 'POST':
        medicine_id = request.POST.get('medicine_id')
        try:
            medicine = WarehouseItem.objects.get(id=medicine_id)
            return JsonResponse({
                'success': True,
                'name': medicine.name,
                'available_quantity': medicine.quantity,
                'unit_price': str(medicine.unit_price),
                'category': medicine.category.name if medicine.category else ''
            })
        except WarehouseItem.DoesNotExist:
            return JsonResponse({'success': False, 'message': 'دارو پیدا نشد.'})

    return JsonResponse({'success': False, 'message': 'درخواست نامعتبر.'})





class WarehouseListView(View):
    # Class configuration
    items_per_page = 8
    allowed_filters = ['name', 'category']
    allowed_sort_fields = ['id', 'name', 'category__name', 'quantity']
    
    def get(self, request):
        # Input validation and sanitization
        search_query = escape(request.GET.get('searchQuery', '').strip())
        filter_type = request.GET.get('filterType', 'name')
        sort_by = request.GET.get('sort', 'id')
        page = request.GET.get('page', request.session.get('last_page', 1))

        # Store current page in session
        request.session['last_page'] = page

        if filter_type not in self.allowed_filters:
            filter_type = 'name'
        
        if sort_by not in self.allowed_sort_fields:
            sort_by = 'id'

        # Optimize query with select_related
        warehouse_items = WarehouseItem.objects.select_related('category').all()

        # Apply filters if search query exists
        if search_query:
            try:
                if filter_type == 'name':
                    warehouse_items = warehouse_items.filter(
                        Q(name__icontains=search_query) |
                        Q(description__icontains=search_query)
                    )
                elif filter_type == 'category':
                    warehouse_items = warehouse_items.filter(
                        category__name__icontains=search_query
                    )
            except ValidationError:
                warehouse_items = WarehouseItem.objects.none()

        # Apply sorting
        warehouse_items = warehouse_items.order_by(sort_by)

        # Pagination
        try:
            page_number = max(1, int(request.GET.get('page', 1)))
        except (ValueError, TypeError):
            page_number = 1

        paginator = Paginator(warehouse_items, self.items_per_page)
        try:
            page_obj = paginator.page(page_number)
        except:
            page_obj = paginator.page(1)

        context = {
            'page_obj': page_obj,
            'search_query': search_query,
            'filter_type': filter_type,
            'sort_by': sort_by,
            'allowed_sort_fields': self.allowed_sort_fields,
            'current_page': page
        }

        return render(request, 'warehouse/warehouse_list.html', context)    
    
    
class WarehouseDetailView(View):
    def get(self, request, pk):
        # Get pagination and search parameters from the query string
        current_page = request.GET.get('page')
        search_query = request.GET.get('searchQuery', '')
        filter_type = request.GET.get('filterType', 'name')
        sort_by = request.GET.get('sort', 'id')
        
        # Get warehouse item
        warehouse_item = get_object_or_404(WarehouseItem, pk=pk)
        
        # Add all parameters to context
        context = {
            'warehouse_item': warehouse_item,
            'page': current_page,
            'search_query': search_query, 
            'filter_type': filter_type,
            'sort_by': sort_by
        }
        
        return render(request, 'warehouse/warehouse_detail.html', context)
    
class WarehouseCreateView(View):
    def get(self, request):
        form = WarehouseItemForm()
        last_page = request.GET.get('page', 1)
        return render(request, 'warehouse/warehouse_form.html', {'form': form, 'last_page': last_page})

    def post(self, request):
        form = WarehouseItemForm(request.POST)
        last_page = request.POST.get('page', 1)
        if form.is_valid():
            try:
                warehouse_name = form.cleaned_data['name']
                
                # Check for existing warehouse item with same name
                if WarehouseItem.objects.filter(name__iexact=warehouse_name).exists():
                    messages.error(request, f"An item with the name '{warehouse_name}' already exists.")
                    return render(request, 'warehouse/warehouse_form.html', {'form': form, 'last_page': last_page})

                item = form.save(commit=False)
                item.created_by = request.user
                item.updated_by = request.user
                item.save()

                # Record history
                WarehouseItemHistory.objects.create(
                    item=item,
                    quantity_changed=item.quantity,
                    unit_price_changed=item.unit_price,
                    changed_by=request.user,
                    history_type='creation'
                )
                
                messages.success(request, "Warehouse item created successfully.")
                return redirect('warehouse:warehouse_list')
            except Exception as e:
                messages.error(request, f"Error creating item: {str(e)}")
        else:
            # Add form validation errors to messages
            for field, errors in form.errors.items():
                for error in errors:
                    messages.error(request, f"{field.capitalize()}: {error}")
                    
        return render(request, 'warehouse/warehouse_form.html', {'form': form, 'last_page': last_page})

class WarehouseUpdateView(View):
    template_name = 'warehouse/warehouse_form.html'

    def get(self, request, pk):
        item = get_object_or_404(WarehouseItem, pk=pk)
        form = WarehouseItemForm(instance=item)
        last_page = request.GET.get('page', 1)
        return render(request, self.template_name, {'form': form, 'last_page': last_page})

    def post(self, request, pk):
        try:
            item = get_object_or_404(WarehouseItem.objects.select_related('category'), pk=pk)
            old_quantity = item.quantity
            old_unit_price = item.unit_price
            
            form = WarehouseItemForm(request.POST, instance=item)
            last_page = request.POST.get('page', 1)
            
            if form.is_valid():
                item = form.save(commit=False)
                item.updated_by = request.user
                item.save()

                # Record history if quantity or unit price changed
                if old_quantity != item.quantity or old_unit_price != item.unit_price:
                    WarehouseItemHistory.objects.create(
                        item=item,
                        quantity_changed=item.quantity - old_quantity,
                        unit_price_changed=item.unit_price,
                        changed_by=request.user,
                        history_type='update'
                    )

                messages.success(request, "Warehouse item updated successfully.")
                return redirect('warehouse:warehouse_list')
            else:
                for field, errors in form.errors.items():
                    for error in errors:
                        messages.error(request, f"{field}: {error}")
        except Exception as e:
            messages.error(request, f"Error updating item: {str(e)}")
            
        return render(request, self.template_name, {'form': form, 'last_page': last_page})    
class IncreaseQuantityView(View):
    def post(self, request, pk):
        item = get_object_or_404(WarehouseItem, pk=pk)
        item.quantity += 1
        item.updated_by = request.user
        item.save()
        
        # Record history
        WarehouseItemHistory.objects.create(
            item=item,
            quantity_changed=1,
            changed_by=request.user,
            history_type='update'
        )
        messages.success(request, f"Quantity increased for {item.name}")
        return redirect('warehouse:warehouse_list')

class DecreaseQuantityView(View):
    def post(self, request, pk):
        item = get_object_or_404(WarehouseItem, pk=pk)
        if item.quantity > 0:
            item.quantity -= 1
            item.updated_by = request.user
            item.save()
            
            # Record history
            WarehouseItemHistory.objects.create(
                item=item,
                quantity_changed=-1,
                changed_by=request.user,
                history_type='update'
            )
            messages.success(request, f"Quantity decreased for {item.name}")
        else:
            messages.warning(request, f"Quantity cannot be negative for {item.name}")
        return redirect('warehouse:warehouse_list')


class WarehouseDeleteView(View):
    def post(self, request, pk):
        item = get_object_or_404(WarehouseItem, pk=pk)
        item.delete()
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({'success': True})
        messages.success(request, "Warehouse item deleted successfully.")
        return redirect('warehouse:warehouse_list')


#Category views



class CategoryListView(View):
    def get(self, request):
        # Get search parameters
        search_query = request.GET.get('searchQuery', '')
        filter_type = request.GET.get('filterType', 'name')
        
        categories = Category.objects.all()


        if search_query:
            if filter_type == 'name':
                categories = categories.filter(name__icontains=search_query)
            elif filter_type == 'description':
                categories = categories.filter(description__icontains=search_query)

        categories = categories.order_by('name')

        # Pagination
        paginator = Paginator(categories, 10)  # Show 10 categories per page
        page_number = request.GET.get('page')
        page_obj = paginator.get_page(page_number)

        context = {
            'page_obj': page_obj,
            'search_query': search_query,
            'filter_type': filter_type
        }
        return render(request, 'warehouse/category_list.html', context)


class CategoryCreateView(View):
    def get(self, request):
        form = CategoryForm()
        return render(request, 'warehouse/category_form.html', {'form': form})

    def post(self, request):
        form = CategoryForm(request.POST)
        
        if form.is_valid():
            category_name = form.cleaned_data['name']
            
            # Check for existing category with same name
            if Category.objects.filter(name__iexact=category_name).exists():
                messages.error(request, f"A category with the name '{category_name}' already exists.")
                return render(request, 'warehouse/category_form.html', {'form': form})
            
            try:
                form.save()
                messages.success(request, "Category created successfully.")
                return redirect('warehouse:category_list')
            except Exception as e:
                messages.error(request, f"Error creating category: {str(e)}")
        else:
            # Add form validation errors to messages
            for field, errors in form.errors.items():
                for error in errors:
                    messages.error(request, f"{field.capitalize()}: {error}")
                    
        return render(request, 'warehouse/category_form.html', {'form': form})
class CategoryUpdateView(UpdateView):
    model = Category
    template_name = 'warehouse/category_form.html'
    fields = ['name', 'description']
    success_url = reverse_lazy('warehouse:category_list')
    
class CategoryDeleteView(DeleteView):
    model = Category
    template_name = 'warehouse/category_confirm_delete.html'
    success_url = reverse_lazy('warehouse:category_list')



# Sale 



class SellItemView(View):
    def post(self, request, pk):
        item = get_object_or_404(WarehouseItem, pk=pk)
        quantity_sold = int(request.POST.get('quantity'))
        description = request.POST.get('description')

        if quantity_sold > item.quantity:
            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return JsonResponse({'success': False, 'error': 'Not enough stock available.'})
            messages.error(request, "Not enough stock available.")
            return render(request, 'warehouse/sell_item.html', {'item': item})

        item.quantity -= quantity_sold
        item.save()

        # Record sale history
        WarehouseItemHistory.objects.create(
            item=item,
            quantity_changed=-quantity_sold,
            unit_price_changed=item.unit_price,
            changed_by=request.user,
            description=description,
            history_type='sale'
        )

        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({'success': True})
        messages.success(request, "Item sold successfully.")
        return redirect('warehouse:warehouse_list')



class SaleHistoryView(View):
    def get(self, request, pk):
        item = get_object_or_404(WarehouseItem, pk=pk)
        # Use select_related to optimize the query
        sale_history = (WarehouseItemHistory.objects
                       .filter(item=item)
                       .select_related('changed_by')
                       .order_by('-changed_at'))
        return render(request, 'warehouse/history.html', 
                     {'item': item, 'sale_history': sale_history})