from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.response import Response
from django.contrib.auth.models import User
from datetime import datetime
import base64
import json
import os
import pytz

from human_resource.models import StaffProfile
from megawatt_agents.models import AgentProfile
from megawatt_api.crm_webhook import account_manager_staff_ids_for_order, notify_crm_staff_performance
from megawatt_api.stock_webhook import notify_crm_stock
from megawatt_api.utils import get_available_stock
from sales_and_marketing.models import CommissionSheetInstance, CustomerAccountManager, CustomerOrder, CustomerOrderDocument, CustomerProfile, ProductDiscount, ProductPricing, ProductVAT
from sales_and_marketing.serializers import CustomerOrderItemSerializer, CustomerOrderSerializer
from system_administration.models import CompanyDepartment, CompanyProfile
from system_administration.utils import check_if_system_administrator, create_folder_if_not_exists, create_notifications
from warehouse_management.models import Category, Product
from django.contrib.auth import authenticate, login, logout
from rest_framework.authtoken.models import Token


@api_view(['POST'])
def get_all_customers_based_on_activity(request):
    target_timezone = pytz.timezone('Africa/Nairobi')
    date_format = '%d/%m/%Y, %H:%M'
    payload = {}
    creator_map = {}
    customer_profile_map = {}
    customer_profiles_list = []
    try:
        company_serial_number = request.data["serial_number"]
        customer_is_active = True if request.data["customer_is_active"] == "true" else False
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        all_customer_profiles = []
        all_customer_profiles = company_profile.company_customers.filter(
            recycle_bin=False).order_by(
            "-id")
        for customer_profile in all_customer_profiles:
            if check_if_customer_is_active(customer_profile) == customer_is_active:
                customer_profile_map = {}
                customer_profile_map["customer_profile_id"] = str(
                    customer_profile.id)
                customer_profile_map["customer_first_name"] = customer_profile.customer_first_name
                customer_profile_map["customer_last_name"] = customer_profile.customer_last_name
                customer_profile_map["email_address"] = customer_profile.email_address
                customer_profile_map["phone_number"] = customer_profile.phone_number
                customer_profile_map["customer_title"] = customer_profile.customer_title
                customer_profile_map["company_name"] = customer_profile.company_name
                customer_profile_map["customer_type"] = customer_profile.customer_type
                customer_profile_map["kra_pin"] = customer_profile.kra_pin
                customer_profile_map["certificate_of_registration_number"] = customer_profile.certificate_of_registration_number
                customer_profile_map["is_profile_set"] = "true" if customer_profile.is_profile_set == True else "false"
                customer_profile_map["created_on"] = datetime.strftime(
                    customer_profile.created_on.astimezone(target_timezone), date_format) if customer_profile.created_on is not None else ""
                customer_profile_map["last_updated_on"] = datetime.strftime(
                    customer_profile.last_updated_on.astimezone(target_timezone), date_format) if customer_profile.last_updated_on is not None else ""
                try:
                    customer_account_manager = CustomerAccountManager.objects.get(
                        customer_profile=customer_profile)
                    customer_profile_map["customer_account_manager"] = {
                        "staff_id": str(customer_account_manager.staff_profile.id),
                        "staff_name": f'{customer_account_manager.staff_profile.first_name} {customer_account_manager.staff_profile.last_name}',
                    }
                except Exception:
                    customer_profile_map["customer_account_manager"] = {"staff_id": "", "staff_name": ""}
                customer_profiles_list.append(customer_profile_map)
        payload["customer_profiles_list"] = customer_profiles_list
        return Response({"message": "true", "payload": payload}, status=200)
    except:
        payload["customer_profiles_list"] = customer_profiles_list
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def get_all_customers(request):
    target_timezone = pytz.timezone('Africa/Nairobi')
    date_format = '%d/%m/%Y, %H:%M'
    payload = {}
    creator_map = {}
    customer_profile_map = {}
    customer_profiles_list = []
    try:
        company_serial_number = request.data["serial_number"]
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        all_customer_profiles = []
        all_customer_profiles = company_profile.company_customers.filter(
            recycle_bin=False).order_by(
            "-id")
        for customer_profile in all_customer_profiles:
            customer_profile_map = {}
            customer_profile_map["customer_profile_id"] = str(
                customer_profile.id)
            customer_profile_map["customer_first_name"] = customer_profile.customer_first_name
            customer_profile_map["customer_last_name"] = customer_profile.customer_last_name
            customer_profile_map["email_address"] = customer_profile.email_address
            customer_profile_map["phone_number"] = customer_profile.phone_number
            customer_profile_map["customer_title"] = customer_profile.customer_title
            customer_profile_map["company_name"] = customer_profile.company_name
            customer_profile_map["customer_type"] = customer_profile.customer_type
            customer_profile_map["kra_pin"] = customer_profile.kra_pin
            customer_profile_map["certificate_of_registration_number"] = customer_profile.certificate_of_registration_number
            customer_profile_map["is_profile_set"] = "true" if customer_profile.is_profile_set == True else "false"
            customer_profile_map["created_on"] = datetime.strftime(
                customer_profile.created_on.astimezone(target_timezone), date_format) if customer_profile.created_on is not None else ""
            customer_profile_map["last_updated_on"] = datetime.strftime(
                customer_profile.last_updated_on.astimezone(target_timezone), date_format) if customer_profile.last_updated_on is not None else ""
            try:
                customer_account_manager = CustomerAccountManager.objects.get(
                    customer_profile=customer_profile)
                customer_profile_map["customer_account_manager"] = {
                    "staff_id": str(customer_account_manager.staff_profile.id),
                    "staff_name": f'{customer_account_manager.staff_profile.first_name} {customer_account_manager.staff_profile.last_name}',
                }
            except Exception:
                customer_profile_map["customer_account_manager"] = {"staff_id": "", "staff_name": ""}
            customer_profiles_list.append(customer_profile_map)
        payload["customer_profiles_list"] = customer_profiles_list
        return Response({"message": "true", "payload": payload}, status=200)
    except:
        payload["customer_profiles_list"] = customer_profiles_list
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def get_customer_types(request):
    target_timezone = pytz.timezone('Africa/Nairobi')
    date_format = '%d/%m/%Y, %H:%M'
    company_serial_number = request.data["serial_number"]
    payload = {}
    creator_map = {}
    customer_type_map = {}
    customer_type_list = []
    try:
        company_serial_number = request.data["serial_number"]
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        # get all customer_types and customer counts
        engineering_procurement_contractor = company_profile.company_customers.filter(
            customer_type="engineering_procurement_contractor")
        technician = company_profile.company_customers.filter(
            customer_type="technician")
        reseller = company_profile.company_customers.filter(
            customer_type="reseller")
        financier = company_profile.company_customers.filter(
            customer_type="financier")
        end_user = company_profile.company_customers.filter(
            customer_type="end_user")
        hydraulic_engineers = company_profile.company_customers.filter(
            customer_type="hydraulic_engineers")
        customer_type_map["customer_type"] = "engineering_procurement_contractor"
        customer_type_map["available_customers"] = str(
            engineering_procurement_contractor.count())
        customer_type_list.append(customer_type_map)
        customer_type_map = {}
        #
        customer_type_map["customer_type"] = "technician"
        customer_type_map["available_customers"] = str(
            technician.count())
        customer_type_list.append(customer_type_map)
        customer_type_map = {}
        #
        customer_type_map["customer_type"] = "reseller"
        customer_type_map["available_customers"] = str(
            reseller.count())
        customer_type_list.append(customer_type_map)
        customer_type_map = {}
        #
        customer_type_map["customer_type"] = "financier"
        customer_type_map["available_customers"] = str(
            financier.count())
        customer_type_list.append(customer_type_map)
        customer_type_map = {}
        #
        customer_type_map["customer_type"] = "end_user"
        customer_type_map["available_customers"] = str(
            end_user.count())
        customer_type_list.append(customer_type_map)
        customer_type_map = {}

        customer_type_map["customer_type"] = "hydraulic_engineers"
        customer_type_map["available_customers"] = str(
            hydraulic_engineers.count())
        customer_type_list.append(customer_type_map)

        payload["customer_type_list"] = customer_type_list
        return Response({"message": "true", "payload": payload}, status=200)
    except:
        payload["customer_type_list"] = customer_type_list
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def get_product_categories(request):
    target_timezone = pytz.timezone('Africa/Nairobi')
    date_format = '%d/%m/%Y, %H:%M'
    payload = {}
    category_map = {}
    category_list = []
    payload = {}
    try:
        company_serial_number = request.data["serial_number"]
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        if company_profile:
            all_categories = Category.objects.filter(
                recycle_bin=False).order_by("-id")
            for category in all_categories:
                #if category.category_name != "TRANSPORT FEE":
                category_map = {}
                category_map["category_id"] = str(category.id)
                category_map["category_name"] = category.category_name
                category_map["category_description"] = category.category_description
                category_list.append(category_map)
            payload["category_list"] = category_list
            return Response({"message": "true", "payload": payload}, status=200)
        else:
            payload["category_list"] = category_list
            return Response({"message": "false", "payload": payload}, status=200)
    except:
        payload["category_list"] = category_list
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def get_all_category_products(request):
    target_timezone = pytz.timezone('Africa/Nairobi')
    date_format = '%d/%m/%Y, %H:%M'
    payload = {}
    category_map = {}
    category_list = []
    payload = {}
    product_list = []
    try:
        company_serial_number = request.data["serial_number"]
        category_id = request.data["category_id"]
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        if company_profile:
            category_instance = Category.objects.get(id=int(category_id))
            category_products = category_instance.category_products.filter(
                recycle_bin=False)
            product_map = {}
            product_list = []
            product_image_catalogue_map = {}
            product_image_catalogues_list = []
            payload = {}
            date_format = '%d/%m/%Y, %H:%M'
            for product in category_products:
                product_map = {}
                product_image_catalogues_list = []
                product_features_catalogues_list = []
                product_components_list = []
                product_brands_list = []
                # product_pricing_map = {}  # 0netoone
                # product_discount_map = {}  # onetoone
                # product_vat_map = {}  # onetoone
                product_map["product_id"] = str(product.id)
                product_map["product_name"] = product.product_name
                product_map["stock_keeping_unit"] = product.stock_keeping_unit
                product_map["unit_of_measurement"] = product.unit_of_measurement
                product_map["product_description"] = product.product_description
                # attaching product specific details
                # attaching product images
                product_image_catalogue = product.product_images.all().order_by("-id")
                for product_image in product_image_catalogue:
                    product_image_catalogue_map = {}
                    product_image_catalogue_map["product_image_id"] = str(
                        product_image.id)
                    product_image_catalogue_map["product_image_url"] = product_image.product_image.url
                    product_image_catalogue_map["image_attribute"] = product_image.image_attribute
                    product_image_catalogue_map["use_as_main_image"] = "true" if product_image.use_as_main_image == True else "false"
                    product_image_catalogues_list.append(
                        product_image_catalogue_map)
                product_map["product_image_catalogues_list"] = product_image_catalogues_list
                # attach product features and attributes
                product_features_catalogue = product.product_features.all().order_by("-id")
                for product_feature in product_features_catalogue:
                    product_features_catalogue_map = {}
                    product_features_attributes_list = []
                    product_features_catalogue_map["product_feature_id"] = str(
                        product_feature.id)
                    product_features_catalogue_map["product_feature_title"] = product_feature.product_feature_title
                    # append features attributes
                    product_features_attributes = product_feature.product_feature_attributes.all().order_by("-id")
                    for feature_attribute in product_features_attributes:
                        product_features_attributes_map = {}
                        product_features_attributes_map[
                            "feature_attribute_id"] = str(feature_attribute.id)
                        product_features_attributes_map[
                            "feature_attribute_title"] = feature_attribute.feature_attribute_title
                        product_features_attributes_map[
                            "feature_attribute_description"] = feature_attribute.feature_attribute_description
                        product_features_attributes_list.append(
                            product_features_attributes_map)
                    product_features_catalogue_map["product_features_attributes_list"] = product_features_attributes_list
                    product_features_catalogues_list.append(
                        product_features_catalogue_map)
                product_map["product_features_catalogues_list"] = product_features_catalogues_list
                # attach product components
                product_components = product.product_components.all().order_by("-id")
                for product_component in product_components:
                    product_component_map = {}
                    product_component_map["product_component_id"] = str(
                        product_component.id)
                    product_component_map["component_name"] = product_component.component_name
                    product_component_map["component_quantity"] = product_component.component_quantity
                    product_components_list.append(
                        product_component_map)
                product_map["product_components_list"] = product_components_list
                # attach product brands
                product_brands = product.product_brands.all().order_by("-id")
                for product_brand in product_brands:
                    product_brand_map = {}
                    product_brand_map["product_brand_id"] = str(
                        product_brand.id)
                    product_brand_map["product_brand_name"] = product_brand.product_brand_name
                    product_brand_map["product_brand_description"] = product_brand.product_brand_description
                    product_brands_list.append(product_brand_map)
                product_map["product_brands_list"] = product_brands_list
                # attach product pricing
                try:
                    product_pricing = ProductPricing.objects.get(
                        product=product)
                    # product_pricing_map["product_pricing_id"] = str(
                    #     product_pricing.id)
                    product_map["product_net_price"] = product_pricing.product_net_price
                    product_map["product_net_price_technician"] = product_pricing.product_net_price_technician
                    product_map["product_net_price_reseller"] = product_pricing.product_net_price_reseller
                    product_map["product_net_price_financier"] = product_pricing.product_net_price_financier
                    product_map["product_net_price_engineering_procurement_contractor"] = product_pricing.product_net_price_engineering_procurement_contractor
                    product_map["product_net_price_hydraulic_engineers"] = product_pricing.product_net_price_hydraulic_engineers
                except:
                    # product_pricing_map["product_pricing_id"] = ""
                    product_map["product_net_price"] = ""
                    product_map["product_net_price_technician"] = ""
                    product_map["product_net_price_reseller"] = ""
                    product_map["product_net_price_financier"] = ""
                    product_map["product_net_price_hydraulic_engineers"] = ""
                # product_map["product_pricing_map"] = product_pricing_map
                # attach product discount
                try:
                    product_discount = ProductDiscount.objects.get(
                        product=product)
                    # product_discount_map["product_discount_id"] = str(
                    #     product_discount.id)
                    product_map["discount_type"] = product_discount.discount_type
                    product_map["discount_value"] = product_discount.discount_value
                except:
                    # product_discount_map["product_discount_id"] = ""
                    product_map["discount_type"] = ""
                    product_map["discount_value"] = ""
                # product_map["product_discount_map"] = product_discount_map
                # attach product vat
                try:
                    product_vat = ProductVAT.objects.get(
                        product=product)
                    # product_vat_map["product_vat_id"] = str(
                    #     product_vat.id)
                    product_map["vat_percentage_value"] = product_vat.vat_percentage_value
                except:
                    # product_vat_map["product_vat_id"] = ""
                    product_map["vat_percentage_value"] = ""
                # product_map["product_vat_map"] = product_vat_map
                product_map["available_stock_quantity"] = f"{get_available_stock(product)}"
                product_list.append(product_map)
            payload["product_list"] = product_list
            return Response({"message": "true", "payload": payload}, status=200)
        else:
            payload["product_list"] = product_list
            return Response({"message": "false", "payload": payload}, status=404)
    except Exception as e:
        print(e)
        payload["product_list"] = product_list
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def get_all_products(request):
    target_timezone = pytz.timezone('Africa/Nairobi')
    date_format = '%d/%m/%Y, %H:%M'
    payload = {}
    category_map = {}
    category_list = []
    payload = {}
    product_list = []
    try:
        company_serial_number = request.data["serial_number"]
        # category_id = request.data["category_id"]
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        if company_profile:
            # category_instance = Category.objects.get(id=int(category_id))
            all_products = Product.objects.filter(
                recycle_bin=False, category__isnull=False)
            product_map = {}
            product_list = []
            product_image_catalogue_map = {}
            product_image_catalogues_list = []
            payload = {}
            date_format = '%d/%m/%Y, %H:%M'
            for product in all_products:
                #if product.category.category_name != "TRANSPORT FEE":
                product_map = {}
                product_image_catalogues_list = []
                product_features_catalogues_list = []
                product_components_list = []
                product_brands_list = []
                # product_pricing_map = {}  # 0netoone
                # product_discount_map = {}  # onetoone
                # product_vat_map = {}  # onetoone
                product_map["product_id"] = str(product.id)
                product_map["category_id"] = str(product.category.id)
                product_map["category_name"] = product.category.category_name
                product_map["product_name"] = product.product_name
                product_map["stock_keeping_unit"] = product.stock_keeping_unit
                product_map["unit_of_measurement"] = product.unit_of_measurement
                product_map["product_description"] = product.product_description
                # attaching product specific details
                # attaching product images
                product_image_catalogue = product.product_images.all().order_by("-id")
                for product_image in product_image_catalogue:
                    product_image_catalogue_map = {}
                    product_image_catalogue_map["product_image_id"] = str(
                        product_image.id)
                    product_image_catalogue_map["product_image_url"] = product_image.product_image.url
                    product_image_catalogue_map["image_attribute"] = product_image.image_attribute
                    product_image_catalogue_map["use_as_main_image"] = "true" if product_image.use_as_main_image == True else "false"
                    product_image_catalogues_list.append(
                        product_image_catalogue_map)
                product_map["product_image_catalogues_list"] = product_image_catalogues_list
                # attach product features and attributes
                product_features_catalogue = product.product_features.all().order_by("-id")
                for product_feature in product_features_catalogue:
                    product_features_catalogue_map = {}
                    product_features_attributes_list = []
                    product_features_catalogue_map["product_feature_id"] = str(
                        product_feature.id)
                    product_features_catalogue_map["product_feature_title"] = product_feature.product_feature_title
                    # append features attributes
                    product_features_attributes = product_feature.product_feature_attributes.all().order_by("-id")
                    for feature_attribute in product_features_attributes:
                        product_features_attributes_map = {}
                        product_features_attributes_map[
                            "feature_attribute_id"] = str(feature_attribute.id)
                        product_features_attributes_map[
                            "feature_attribute_title"] = feature_attribute.feature_attribute_title
                        product_features_attributes_map[
                            "feature_attribute_description"] = feature_attribute.feature_attribute_description
                        product_features_attributes_list.append(
                            product_features_attributes_map)
                    product_features_catalogue_map["product_features_attributes_list"] = product_features_attributes_list
                    product_features_catalogues_list.append(
                        product_features_catalogue_map)
                product_map["product_features_catalogues_list"] = product_features_catalogues_list
                # attach product components
                product_components = product.product_components.all().order_by("-id")
                for product_component in product_components:
                    product_component_map = {}
                    product_component_map["product_component_id"] = str(
                        product_component.id)
                    product_component_map["component_name"] = product_component.component_name
                    product_component_map["component_quantity"] = product_component.component_quantity
                    product_components_list.append(
                        product_component_map)
                product_map["product_components_list"] = product_components_list
                # attach product brands
                product_brands = product.product_brands.all().order_by("-id")
                for product_brand in product_brands:
                    product_brand_map = {}
                    product_brand_map["product_brand_id"] = str(
                        product_brand.id)
                    product_brand_map["product_brand_name"] = product_brand.product_brand_name
                    product_brand_map["product_brand_description"] = product_brand.product_brand_description
                    product_brands_list.append(product_brand_map)
                product_map["product_brands_list"] = product_brands_list
                # attach product pricing
                try:
                    product_pricing = ProductPricing.objects.get(
                        product=product)
                    # product_pricing_map["product_pricing_id"] = str(
                    #     product_pricing.id)
                    product_map["product_net_price"] = product_pricing.product_net_price
                    # product_pricing_map["product_net_price_technician"] = product_pricing.product_net_price_technician
                    # product_pricing_map["product_net_price_reseller"] = product_pricing.product_net_price_reseller
                    # product_pricing_map["product_net_price_financier"] = product_pricing.product_net_price_financier
                    # product_pricing_map["product_net_price_engineering_procurement_contractor"] = product_pricing.product_net_price_engineering_procurement_contractor
                except:
                    # product_pricing_map["product_pricing_id"] = ""
                    product_map["product_net_price"] = ""
                    # product_pricing_map["product_net_price_technician"] = ""
                    # product_pricing_map["product_net_price_reseller"] = ""
                    # product_pricing_map["product_net_price_financier"] = ""
                    # product_pricing_map["product_net_price_engineering_procurement_contractor"] = ""
                # product_map["product_pricing_map"] = product_pricing_map
                # attach product discount
                try:
                    product_discount = ProductDiscount.objects.get(
                        product=product)
                    # product_discount_map["product_discount_id"] = str(
                    #     product_discount.id)
                    product_map["discount_type"] = product_discount.discount_type
                    product_map["discount_value"] = product_discount.discount_value
                except:
                    # product_discount_map["product_discount_id"] = ""
                    product_map["discount_type"] = ""
                    product_map["discount_value"] = ""
                # product_map["product_discount_map"] = product_discount_map
                # attach product vat
                try:
                    product_vat = ProductVAT.objects.get(
                        product=product)
                    # product_vat_map["product_vat_id"] = str(
                    #     product_vat.id)
                    product_map["vat_percentage_value"] = product_vat.vat_percentage_value
                except:
                    # product_vat_map["product_vat_id"] = ""
                    product_map["vat_percentage_value"] = ""
                # product_map["product_vat_map"] = product_vat_map
                product_map["available_stock_quantity"] = f"{get_available_stock(product)}"
                product_list.append(product_map)
            payload["product_list"] = product_list
            return Response({"message": "true", "payload": payload}, status=200)
        else:
            payload["product_list"] = product_list
            return Response({"message": "false", "payload": payload}, status=404)
    except Exception as e:
        print(e)
        payload["product_list"] = product_list
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def get_all_staff_sales_performance(request):
    date_format = '%d/%m/%Y'
    target_timezone = pytz.timezone('Africa/Nairobi')
    active_user = request.user
    payload = {}
    customer_profile_map = {}
    customer_profiles_list = []
    # customer_order_map = {}
    # customer_orders_list = []
    # customer_order_item_map = {}
    # customer_order_items_list = []
    account_manager_map = {}
    staff_list = []
    try:
        company_serial_number = request.data["serial_number"]
        date_from = datetime.strptime(request.data["date_from"], date_format)
        date_to = datetime.strptime(request.data["date_to"], date_format).replace(hour=23, minute=59, second=59, microsecond=999999)
        staff_profiles = StaffProfile.objects.filter(
            recycle_bin=False, is_profile_active=True)
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        for staff_profile in staff_profiles:
            account_manager_map = {}
            customer_profiles_list = []
            managed_customer_accounts = staff_profile.staff_customer_accounts.all().order_by("-id")
            account_manager_map["staff_id"] = str(staff_profile.id)
            account_manager_map["first_name"] = staff_profile.first_name
            account_manager_map["last_name"] = staff_profile.last_name
            account_manager_map["staff_number"] = staff_profile.staff_number
            # account_manager_map["preferred_currency"] = company_profile.company_preferred_currency
            for customer_account in managed_customer_accounts:
                customer_profile = customer_account.customer_profile
                customer_profile_map = {}
                shopping_history = []
                customer_profile_map["customer_profile_id"] = str(
                    customer_profile.id)
                customer_profile_map["customer_first_name"] = customer_profile.customer_first_name
                customer_profile_map["customer_last_name"] = customer_profile.customer_last_name
                customer_profile_map["email_address"] = customer_profile.email_address
                customer_profile_map["phone_number"] = customer_profile.phone_number
                customer_profile_map["customer_title"] = customer_profile.customer_title
                customer_profile_map["company_name"] = customer_profile.company_name
                customer_profile_map["customer_type"] = customer_profile.customer_type
                customer_profile_map["is_profile_set"] = "true" if customer_profile.is_profile_set == True else "false"
                customer_profile_map["created_on"] = datetime.strftime(
                    customer_profile.created_on.astimezone(target_timezone), date_format) if customer_profile.created_on is not None else ""
                customer_profile_map["last_updated_on"] = datetime.strftime(
                    customer_profile.last_updated_on.astimezone(target_timezone), date_format) if customer_profile.last_updated_on is not None else ""
                customer_order_history = customer_profile.customer_order_history.filter(
                    # greater than or equal to date_from
                    recycle_bin=False,
                    customer_order_approved=True, created_on__gte=date_from,
                    created_on__lte=date_to).order_by("-id")
                for customer_order in customer_order_history:
                    order_map = {}
                    order_item_list = []
                    order_map["customer_order_number"] = customer_order.customer_order_number
                    order_map["customer_order_total_gross_value"] = customer_order.customer_order_total_gross_value
                    order_map["customer_order_total_discount"] = customer_order.customer_order_total_discount
                    order_map["customer_order_total_net_value"] = customer_order.customer_order_total_net_value
                    order_map["customer_order_total_amount_paid"] = customer_order.customer_order_total_amount_paid
                    order_map["created_on"] = datetime.strftime(
                        customer_order.created_on.astimezone(target_timezone), date_format) if customer_order.created_on is not None else ""
                    # to be updated
                    order_map["currency"] = company_profile.company_preferred_currency
                    customer_order_items = customer_order.customer_order_items.all()
                    for order_item in customer_order_items:
                        order_item_map = {}
                        order_item_map["customer_order_number"] = customer_order.customer_order_number
                        order_item_map["product_name"] = order_item.product.product_name
                        order_item_map["quantity"] = order_item.quantity
                        order_item_map["price_per_item"] = order_item.price_per_item
                        order_item_map["discount_per_item"] = order_item.discount_per_item
                        order_item_map["net_subtotal"] = order_item.net_subtotal
                        order_item_map["gross_subtotal"] = order_item.gross_subtotal
                        order_item_map["total_discount"] = order_item.total_discount
                        order_item_map["created_on"] = datetime.strftime(
                            customer_order.created_on.astimezone(target_timezone), date_format) if customer_order.created_on is not None else ""
                        order_item_map["sales_item_order_fulfilled"] = "true" if order_item.sales_item_order_fulfilled == True else "false"
                        # order_item_map["last_updated_on"] = datetime.strftime(
                        #     customer_order.last_updated_on.astimezone(target_timezone), date_format) if customer_order.last_updated_on is not None else ""
                        order_item_list.append(order_item_map)
                    order_map["order_item_list"] = order_item_list
                    shopping_history.append(order_map)
                customer_profile_map["shopping_history"] = shopping_history
                customer_profiles_list.append(customer_profile_map)
            account_manager_map["customer_profiles_list"] = customer_profiles_list
            staff_list.append(account_manager_map)
        payload["staff_list"] = staff_list
        return Response({"message": "true", "payload": payload}, status=200)
    except Exception as e:
        print(e)
        payload["staff_list"] = staff_list
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def get_all_staff_commissions(request):
    date_format = '%d/%m/%Y'
    target_timezone = pytz.timezone('Africa/Nairobi')
    active_user = request.user
    payload = {}
    commission_map = {}
    commission_list = []
    # customer_order_map = {}
    # customer_orders_list = []
    # customer_order_item_map = {}
    # customer_order_items_list = []
    staff_map = {}
    staff_list = []
    try:
        date_from = datetime.strptime(request.data["date_from"], date_format)
        date_to = datetime.strptime(request.data["date_to"], date_format)
        company_serial_number = request.data["serial_number"]
        staff_profiles = StaffProfile.objects.filter(
            recycle_bin=False, is_profile_active=True)
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        for staff_profile in staff_profiles:
            staff_map = {}
            staff_map["staff_id"] = str(staff_profile.id)
            staff_map["first_name"] = staff_profile.first_name
            staff_map["last_name"] = staff_profile.last_name
            staff_map["staff_number"] = staff_profile.staff_number
            staff_payroll_instances = staff_profile.staff_payroll_instance.filter(
                recycle_bin=False,)
            staff_commissions_list = []
            for payroll_instance in staff_payroll_instances:
                if float(payroll_instance.commissions_total) > 0:
                    commission_map = {}
                    commission_map["payroll_sheet_id"] = str(
                        payroll_instance.payroll_sheet.id)
                    commission_map["staff_payroll_instance_id"] = str(
                        payroll_instance.id)
                    commission_map["currency"] = company_profile.company_preferred_currency
                    print(payroll_instance.commissions_total)
                    commission_sheet_instance = CommissionSheetInstance.objects.get(
                        staff_payroll_instance=payroll_instance)
                    commission_map["commission_sheet_for_the_month_of"] = commission_sheet_instance.commission_sheet.commission_sheet_for_the_month_of
                    commission_map["commission_sheet_for_the_year"] = commission_sheet_instance.commission_sheet.commission_sheet_for_the_year
                    commission_map["commission_value"] = commission_sheet_instance.commissions_total
                    if commission_sheet_instance.commission_sheet.commission_sheet_approved_by_finance:
                        staff_commissions_list.append(commission_map)
            staff_map["staff_commissions_list"] = staff_commissions_list
            staff_list.append(staff_map)
        payload["staff_list"] = staff_list
        return Response({"message": "true", "payload": payload}, status=200)
    except Exception as e:
        print(e)
        payload["staff_list"] = staff_list
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def get_single_staff_sales_performance(request):
    date_format = '%d/%m/%Y'
    target_timezone = pytz.timezone('Africa/Nairobi')
    active_user = request.user
    payload = {}
    customer_profile_map = {}
    customer_profiles_list = []
    # customer_order_map = {}
    # customer_orders_list = []
    # customer_order_item_map = {}
    # customer_order_items_list = []
    account_manager_map = {}
    # staff_list = []
    try:
        company_serial_number = request.data["serial_number"]
        staff_id = request.data["staff_id"]
        date_from = datetime.strptime(request.data["date_from"], date_format)
        date_to = datetime.strptime(request.data["date_to"], date_format).replace(hour=23, minute=59, second=59, microsecond=999999)
        # staff_profiles = StaffProfile.objects.filter(
        #     recycle_bin=False, is_profile_active=True)
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        staff_profile = StaffProfile.objects.get(id=int(staff_id))
        # for staff_profile in staff_profiles:
        account_manager_map = {}
        customer_profiles_list = []
        managed_customer_accounts = staff_profile.staff_customer_accounts.all().order_by("-id")
        account_manager_map["staff_id"] = str(staff_profile.id)
        account_manager_map["first_name"] = staff_profile.first_name
        account_manager_map["last_name"] = staff_profile.last_name
        account_manager_map["staff_number"] = staff_profile.staff_number
        # account_manager_map["preferred_currency"] = company_profile.company_preferred_currency
        for customer_account in managed_customer_accounts:
            customer_profile = customer_account.customer_profile
            customer_profile_map = {}
            shopping_history = []
            customer_profile_map["customer_profile_id"] = str(
                customer_profile.id)
            customer_profile_map["customer_first_name"] = customer_profile.customer_first_name
            customer_profile_map["customer_last_name"] = customer_profile.customer_last_name
            customer_profile_map["email_address"] = customer_profile.email_address
            customer_profile_map["phone_number"] = customer_profile.phone_number
            customer_profile_map["customer_title"] = customer_profile.customer_title
            customer_profile_map["company_name"] = customer_profile.company_name
            customer_profile_map["customer_type"] = customer_profile.customer_type
            customer_profile_map["is_profile_set"] = "true" if customer_profile.is_profile_set == True else "false"
            customer_profile_map["created_on"] = datetime.strftime(
                customer_profile.created_on.astimezone(target_timezone), date_format) if customer_profile.created_on is not None else ""
            customer_profile_map["last_updated_on"] = datetime.strftime(
                customer_profile.last_updated_on.astimezone(target_timezone), date_format) if customer_profile.last_updated_on is not None else ""
            customer_order_history = customer_profile.customer_order_history.filter(
                # greater than or equal to date_from
                recycle_bin=False,
                customer_order_approved=True, created_on__gte=date_from,
                created_on__lte=date_to).order_by("-id")
            for customer_order in customer_order_history:
                order_map = {}
                order_item_list = []
                order_map["customer_order_number"] = customer_order.customer_order_number
                order_map["customer_order_total_gross_value"] = customer_order.customer_order_total_gross_value
                order_map["customer_order_total_discount"] = customer_order.customer_order_total_discount
                order_map["customer_order_total_net_value"] = customer_order.customer_order_total_net_value
                order_map["customer_order_total_amount_paid"] = customer_order.customer_order_total_amount_paid
                order_map["created_on"] = datetime.strftime(
                    customer_order.created_on.astimezone(target_timezone), date_format) if customer_order.created_on is not None else ""
                # to be updated
                order_map["currency"] = company_profile.company_preferred_currency
                customer_order_items = customer_order.customer_order_items.all()
                for order_item in customer_order_items:
                    order_item_map = {}
                    order_item_map["customer_order_number"] = customer_order.customer_order_number
                    order_item_map["product_name"] = order_item.product.product_name
                    order_item_map["quantity"] = order_item.quantity
                    order_item_map["price_per_item"] = order_item.price_per_item
                    order_item_map["discount_per_item"] = order_item.discount_per_item
                    order_item_map["net_subtotal"] = order_item.net_subtotal
                    order_item_map["gross_subtotal"] = order_item.gross_subtotal
                    order_item_map["total_discount"] = order_item.total_discount
                    order_item_map["created_on"] = datetime.strftime(
                        customer_order.created_on.astimezone(target_timezone), date_format) if customer_order.created_on is not None else ""
                    order_item_map["sales_item_order_fulfilled"] = "true" if order_item.sales_item_order_fulfilled == True else "false"
                    # order_item_map["last_updated_on"] = datetime.strftime(
                    #     customer_order.last_updated_on.astimezone(target_timezone), date_format) if customer_order.last_updated_on is not None else ""
                    order_item_list.append(order_item_map)
                order_map["order_item_list"] = order_item_list
                shopping_history.append(order_map)
            customer_profile_map["shopping_history"] = shopping_history
            customer_profiles_list.append(customer_profile_map)
            account_manager_map["customer_profiles_list"] = customer_profiles_list
            # staff_list.append(account_manager_map)
        payload["staff_map"] = account_manager_map
        return Response({"message": "true", "payload": payload}, status=200)
    except Exception as e:
        print(e)
        payload["staff_map"] = []
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def get_single_staff_commissions(request):
    date_format = '%d/%m/%Y'
    target_timezone = pytz.timezone('Africa/Nairobi')
    active_user = request.user
    payload = {}
    commission_map = {}
    commission_list = []
    # customer_order_map = {}
    # customer_orders_list = []
    # customer_order_item_map = {}
    # customer_order_items_list = []
    staff_map = {}
    staff_list = []
    try:
        date_from = datetime.strptime(request.data["date_from"], date_format)
        date_to = datetime.strptime(request.data["date_to"], date_format)
        company_serial_number = request.data["serial_number"]
        staff_id = request.data["staff_id"]
        staff_profile = StaffProfile.objects.get(id=int(staff_id))
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        # for staff_profile in staff_profiles:
        staff_map = {}
        staff_map["staff_id"] = str(staff_profile.id)
        staff_map["first_name"] = staff_profile.first_name
        staff_map["last_name"] = staff_profile.last_name
        staff_map["staff_number"] = staff_profile.staff_number
        staff_payroll_instances = staff_profile.staff_payroll_instance.filter(
            recycle_bin=False,)
        staff_commissions_list = []
        for payroll_instance in staff_payroll_instances:
            if float(payroll_instance.commissions_total) > 0:
                commission_map = {}
                commission_map["payroll_sheet_id"] = str(
                    payroll_instance.payroll_sheet.id)
                commission_map["staff_payroll_instance_id"] = str(
                    payroll_instance.id)
                commission_map["currency"] = company_profile.company_preferred_currency
                print(payroll_instance.commissions_total)
                commission_sheet_instance = CommissionSheetInstance.objects.get(
                    staff_payroll_instance=payroll_instance)
                commission_map["commission_sheet_for_the_month_of"] = commission_sheet_instance.commission_sheet.commission_sheet_for_the_month_of
                commission_map["commission_sheet_for_the_year"] = commission_sheet_instance.commission_sheet.commission_sheet_for_the_year
                commission_map["commission_value"] = commission_sheet_instance.commissions_total
                if commission_sheet_instance.commission_sheet.commission_sheet_approved_by_finance:
                    staff_commissions_list.append(commission_map)
        staff_map["staff_commissions_list"] = staff_commissions_list
        staff_list.append(staff_map)
        payload["staff_map"] = staff_map
        return Response({"message": "true", "payload": payload}, status=200)
    except Exception as e:
        print(e)
        payload["staff_map"] = []
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def agent_login(request):
    target_timezone = pytz.timezone('Africa/Nairobi')
    date_format = '%d/%m/%Y, %H:%M'
    payload = {}
    category_map = {}
    category_list = []
    payload = {}
    try:
        username = request.data['username']
        password = request.data['password']
        # agent_profile = AgentProfile.objects.get(agent_number=agent_number)
        # username = agent_profile.user.username
        # print(username)
        user = authenticate(request, username=username, password=password)
        agent_profile = user.user_agent_profile
        if user is not None and agent_profile.is_profile_active == True:
            login(request, user)
            # token = token, created = Token.objects.get_or_create(user=user)
            # payload["company_department"] = staff_profile.company_department.department_name if staff_profile.company_department is not None else "not_assigned"
            # full_name = f'{staff_profile.first_name} {staff_profile.last_name}' if len(
            #     staff_profile.first_name) > 0 and len(staff_profile.last_name) > 0 else "No Name"
            # user_role = f'{staff_profile.staff_position.position_title}' if staff_profile.staff_position is not None else "Not Assigned"
            payload["first_name"] = agent_profile.first_name
            payload["last_name"] = agent_profile.last_name
            payload["agent_id"] = str(agent_profile.id)
            payload["email_address"] = agent_profile.user.username
            payload["phone_number"] = agent_profile.phone_number
            payload["agent_title"] = agent_profile.agent_title
            payload["identification_number"] = agent_profile.identification_number
            payload["agent_number"] = agent_profile.agent_number
            return Response({"message": "Login successful", "payload": payload}, status=200)
        else:
            return Response({"message": "Invalid credentials", "payload": payload}, status=406)
    except Exception as e:
        print(e)
        return Response({"message": "Error logging in agent", "payload": payload}, status=500)


@api_view(['POST'])
def change_password_for_agent(request):
    payload = {}
    try:
        username = request.data['username']
        old_password = request.data['old_password']
        new_password = request.data['new_password']
        user = authenticate(request, username=username, password=old_password)
        if user is not None:
            agent_profile = getattr(user, 'user_agent_profile', None)
            if agent_profile is not None and agent_profile.is_profile_active:
                user.set_password(new_password)
                user.save()
                return Response({"message": "Password changed successfully", "payload": payload}, status=200)
        return Response({"message": "Invalid credentials", "payload": payload}, status=406)
    except Exception as e:
        print(e)
        return Response({"message": "Error changing password", "payload": payload}, status=500)


@api_view(['POST'])
def get_access_token(request):
    """Issue an auth token by username/email.

    Contract (live ERP, consumed by the CRM and the ERP Vue frontend login
    fallback): POST {"user_name": <email>} -> {"payload": {"user_token": ...}}.
    Falls back to the legacy {"username","password"} agent form. Returns the
    token under both `user_token` and `token` for backward compatibility.
    """
    payload = {}
    try:
        user_name = request.data.get('user_name') or request.data.get('username')
        password = request.data.get('password')
        if not user_name:
            return Response({"message": "Invalid credentials", "payload": payload}, status=406)

        try:
            user = User.objects.get(username=user_name)
        except User.DoesNotExist:
            return Response({"message": "Invalid credentials", "payload": payload}, status=406)

        staff_profile = StaffProfile.objects.filter(user=user).first()
        agent_profile = getattr(user, 'user_agent_profile', None)

        # Staff (CRM + ERP frontend) — token by username, mirroring the live ERP.
        if staff_profile is not None:
            authorized = True
        # Agent — preserve the legacy password check when supplied.
        elif agent_profile is not None and agent_profile.is_profile_active:
            authorized = (password is None) or (
                authenticate(request, username=user_name, password=password) is not None)
        else:
            authorized = False

        if not authorized:
            return Response({"message": "Invalid credentials", "payload": payload}, status=406)

        try:
            login(request, user)
        except Exception:
            pass
        token, _created = Token.objects.get_or_create(user=user)
        payload["user_token"] = token.key
        payload["token"] = token.key
        return Response({"message": "Login successful", "payload": payload}, status=200)
    except Exception as e:
        print(e)
        return Response({"message": "Error getting access token", "payload": payload}, status=500)


def check_if_customer_is_active(customer_profile):
    is_active = False
    customer_order_history = customer_profile.customer_order_history.filter(
        customer_order_approved=True, recycle_bin=False)
    for order in customer_order_history:
        if float(order.customer_order_total_net_value) > 0:
            is_active = True
            break
    return is_active


# ---------------------------------------------------------------------------
# CRM INTEGRATION ENDPOINTS  (ported from live ERP — consumed by the Laravel CRM)
# ---------------------------------------------------------------------------

@api_view(['POST'])
def check_if_customer_order_exist(request):
    quote_number = request.data["quote_number"]
    try:
        customer_order = CustomerOrder.objects.get(
            customer_order_description=quote_number,)
        if customer_order is not None:
            return Response({"message": "true", }, status=200)
    except Exception as e:
        print(e)
        return Response({"message": "false", }, status=200)


@api_view(['POST'])
def get_customer_by_email(request):
    target_timezone = pytz.timezone('Africa/Nairobi')
    date_format = '%d/%m/%Y, %H:%M'
    payload = {}
    company_serial_number = request.data.get("serial_number", "")
    email_address = request.data.get("email_address", "")

    if not company_serial_number or not email_address:
        return Response({"message": "false", "payload": payload}, status=200)

    try:
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
    except CompanyProfile.DoesNotExist:
        return Response({"message": "false", "payload": payload}, status=200)

    customer_profile = company_profile.company_customers.filter(
        email_address__iexact=email_address,
        recycle_bin=False
    ).first()
    if customer_profile is None:
        return Response({"message": "false", "payload": payload}, status=200)

    payload["customer_profile_id"] = str(customer_profile.id)
    payload["customer_first_name"] = customer_profile.customer_first_name
    payload["customer_last_name"] = customer_profile.customer_last_name
    payload["email_address"] = customer_profile.email_address
    payload["phone_number"] = customer_profile.phone_number
    payload["customer_title"] = customer_profile.customer_title
    payload["company_name"] = customer_profile.company_name
    payload["customer_type"] = customer_profile.customer_type
    payload["kra_pin"] = customer_profile.kra_pin
    payload["certificate_of_registration_number"] = customer_profile.certificate_of_registration_number
    payload["is_profile_set"] = "true" if customer_profile.is_profile_set == True else "false"
    payload["created_on"] = datetime.strftime(
        customer_profile.created_on.astimezone(target_timezone), date_format) if customer_profile.created_on is not None else ""
    payload["last_updated_on"] = datetime.strftime(
        customer_profile.last_updated_on.astimezone(target_timezone), date_format) if customer_profile.last_updated_on is not None else ""
    try:
        customer_account_manager = CustomerAccountManager.objects.get(
            customer_profile=customer_profile)
        account_manager_map = {}
        account_manager_map["staff_id"] = str(
            customer_account_manager.staff_profile.id)
        account_manager_map["staff_name"] = f'{customer_account_manager.staff_profile.first_name} {customer_account_manager.staff_profile.last_name}'
        payload["customer_account_manager"] = account_manager_map
    except Exception:
        payload["customer_account_manager"] = {"staff_id": "", "staff_name": ""}

    return Response({"message": "true", "payload": payload}, status=200)


@api_view(['POST'])
def get_all_marketing_staff(request):
    payload = {}
    staff_profile_list = []
    try:
        company_serial_number = request.data["serial_number"]
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        if company_profile:
            all_staff = StaffProfile.objects.filter(
                recycle_bin=False, is_profile_active=True, is_profile_set=True)
            for staff in all_staff:
                staff_map = {}
                staff_map["staff_id"] = str(staff.id)
                staff_map["email_address"] = staff.user.username if staff.user is not None else ""
                staff_map["staff_position"] = staff.staff_position.position_title if staff.staff_position is not None else ""
                staff_map["staff_number"] = staff.staff_number
                staff_map["first_name"] = staff.first_name
                staff_map["last_name"] = staff.last_name
                staff_map["phone_number"] = staff.phone_number
                staff_map["staff_title"] = staff.staff_title
                staff_map["company_branch_name"] = staff.company_branch.branch_name if staff.company_branch is not None else ""
                staff_map["company_department"] = staff.company_department.department_name if staff.company_department is not None else ""
                staff_map["is_head_of_department"] = "true" if staff.is_head_of_department else "false"
                staff_map["is_super_admin"] = "true" if staff.is_super_admin else "false"
                staff_map["is_profile_active"] = "true" if staff.is_profile_active == True else "false"
                staff_profile_list.append(staff_map)
            payload["staff_profile_list"] = staff_profile_list
            return Response({"message": "true", "payload": payload}, status=200)
        else:
            payload["staff_profile_list"] = staff_profile_list
            return Response({"message": "false", "payload": payload}, status=406)
    except Exception as e:
        print(e)
        payload["staff_profile_list"] = staff_profile_list
        return Response({"message": "false", "payload": payload}, status=500)


@api_view(['POST'])
def marketing_login(request):
    payload = {}
    try:
        staff_number = request.data['staff_number']
        password = request.data['password']
        staff_profile = StaffProfile.objects.get(staff_number=staff_number)
        username = staff_profile.user.username
        user = authenticate(request, username=username, password=password)
        if user is not None and staff_profile.is_profile_active == True:
            login(request, user)
            payload["company_department"] = staff_profile.company_department.department_name if staff_profile.company_department is not None else "not_assigned"
            user_role = f'{staff_profile.staff_position.position_title}' if staff_profile.staff_position is not None else "Not Assigned"
            payload["first_name"] = staff_profile.first_name
            payload["last_name"] = staff_profile.last_name
            payload["user_role"] = user_role
            payload["staff_id"] = str(staff_profile.id)
            payload["email_address"] = staff_profile.user.username
            payload["phone_number"] = staff_profile.phone_number
            payload["branch_name"] = staff_profile.company_branch.branch_name if staff_profile.company_branch is not None else ""
            return Response({"message": "Login successful", "payload": payload}, status=200)
        else:
            return Response({"message": "Invalid credentials", "payload": payload}, status=406)
    except Exception as e:
        print(e)
        return Response({"message": "Error logging in staff", "payload": payload}, status=500)


def _save_crm_order_document(order, document_type, base64_content, original_name):
    """Decode a base64 document pushed from the CRM and persist it against the
    customer order. Returns the CustomerOrderDocument or None."""
    if not base64_content:
        return None
    try:
        content = str(base64_content).strip()
        # strip a possible data-URI prefix (e.g. "data:application/pdf;base64,")
        if content[:5].lower() == "data:" and "," in content:
            content = content.split(",", 1)[1]
        raw = base64.b64decode(content)
        folder_path = create_folder_if_not_exists()
        safe_name = (original_name or f"{document_type}.bin").replace("/", "_").replace("\\", "_")
        file_name = f"{order.customer_order_number}_{document_type}_{safe_name}"
        file_path = os.path.join(folder_path, file_name)
        with open(file_path, "wb") as destination:
            destination.write(raw)
        return CustomerOrderDocument.objects.create(
            customer_order=order,
            document_type=document_type,
            original_name=original_name or safe_name,
            saved_document_path=file_path,
            uploaded_via="crm",
        )
    except Exception as exc:
        print(f"Failed to save CRM order document ({document_type}): {exc}")
        return None


@api_view(['POST'])
def create_customer_order_crm(request):
    date_format = '%d/%m/%Y'
    try:
        company_serial_number = request.data["serial_number"]
        customer_id = request.data["customer_id"]
        customer_order_type = "order_offline"
        customer_order_description = request.data["customer_order_description"]
        customer_order_total_gross_value = request.data["customer_order_total_gross_value"]
        customer_order_total_discount = request.data["customer_order_total_discount"]
        customer_order_total_net_value = request.data["customer_order_total_net_value"]
        customer_order_approved = False
        staff_id = request.data["staff_id"]
        expected_delivery_date = datetime.strptime(
            request.data["expected_delivery_date"], date_format).strftime("%Y-%m-%d") if len(request.data["expected_delivery_date"]) > 0 else None
        customer_order_items_list = request.data.get(
            'customer_order_items_list', [])
        if isinstance(customer_order_items_list, str):
            customer_order_items_list = json.loads(customer_order_items_list)
        elif customer_order_items_list is None:
            customer_order_items_list = []
        staff_profile = StaffProfile.objects.get(id=int(staff_id))
        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        if ((staff_profile.company_department.department_name == "sales" or staff_profile.company_department.department_name == "marketing") and company_profile) or check_if_system_administrator(staff_profile):
            company_branch = staff_profile.company_branch
            customer_profile = None
            if customer_id and len(str(customer_id)) > 0:
                try:
                    user = User.objects.get(username=customer_id)
                    customer_profile = CustomerProfile.objects.filter(
                        user=user).first()
                except User.DoesNotExist:
                    customer_profile = None
                except Exception:
                    customer_profile = None
                if customer_profile is None:
                    customer_profile = CustomerProfile.objects.filter(
                        email_address__iexact=customer_id,
                        recycle_bin=False
                    ).first()
            customer_order_serializer = CustomerOrderSerializer(
                data={'company_branch': company_branch.id, 'customer_profile': customer_profile.id if customer_profile else None, 'customer_order_type': customer_order_type, 'customer_order_description': customer_order_description, 'customer_order_total_gross_value': customer_order_total_gross_value, 'customer_order_total_discount': customer_order_total_discount, 'customer_order_total_net_value': customer_order_total_net_value, 'customer_order_approved': customer_order_approved, 'expected_delivery_date': expected_delivery_date, 'sales_person': staff_profile.id, 'created_by': staff_profile.id, 'last_updated_by': staff_profile.id})
            if customer_order_serializer.is_valid():
                new_order = customer_order_serializer.save()
                new_order.origin = "crm"
                new_order.save(update_fields=["origin"])
                for customer_order_item in customer_order_items_list:
                    product_id = customer_order_item["product_id"]
                    quantity = customer_order_item["quantity"]
                    price_per_item = customer_order_item["price_per_item"]
                    discount_per_item = customer_order_item["discount_per_item"]
                    gross_subtotal = customer_order_item["gross_subtotal"]
                    total_discount = customer_order_item["total_discount"]
                    net_subtotal = customer_order_item["net_subtotal"]
                    order_item_serializer = CustomerOrderItemSerializer(data={'customer_order': new_order.id, 'product': int(
                        product_id), 'quantity': quantity, 'price_per_item': price_per_item, 'discount_per_item': discount_per_item, 'gross_subtotal': gross_subtotal, 'total_discount': total_discount, 'net_subtotal': net_subtotal})
                    if order_item_serializer.is_valid():
                        order_item_serializer.save()
                # persist POP / LPO documents pushed from the CRM (base64)
                _save_crm_order_document(
                    new_order, "lpo",
                    request.data.get("lpo_document"),
                    request.data.get("lpo_document_name"))
                _save_crm_order_document(
                    new_order, "pop",
                    request.data.get("pop_document"),
                    request.data.get("pop_document_name"))
                # Reserve the committed stock in the ERP and broadcast the new
                # availability back to the CRM (two-way stock sync).
                try:
                    from warehouse_management.stock_availability import reserve_stock_for_order
                    affected_product_ids = reserve_stock_for_order(new_order, staff_profile)
                    if affected_product_ids:
                        notify_crm_stock(affected_product_ids)
                except Exception as stock_error:
                    print(stock_error)
                # notify finance department
                try:
                    list_of_staff_ids = []
                    finance_dept = CompanyDepartment.objects.get(
                        department_name="finance_and_accounting")
                    all_finance_staff = StaffProfile.objects.filter(
                        company_department=finance_dept)
                    for finance_staff in all_finance_staff:
                        list_of_staff_ids.append(finance_staff.id)
                    notification_title = f"Customer Order {new_order.customer_order_number}"
                    notification_body = f"A new customer order of number {new_order.customer_order_number} has been created. Approval by finance department is required."
                    create_notifications(notification_title,
                                         notification_body, list_of_staff_ids)
                except Exception:
                    pass
                # Immediately refresh the responsible staff's performance in the CRM
                try:
                    notify_crm_staff_performance(
                        account_manager_staff_ids_for_order(new_order))
                except Exception as perf_error:
                    print(perf_error)
                return Response({"message": f"Customer order {new_order.customer_order_number} created successfully", }, status=200)
            else:
                print(customer_order_serializer.errors)
                return Response({"message": "Error creating customer order", }, status=406)
        else:
            return Response({"message": "You are unauthorized to perform this action", }, status=401)
    except Exception as e:
        print(e)
        return Response({"message": "Error creating customer order", }, status=500)


@api_view(['POST'])
def create_stock_reservation_crm(request):
    """CRM-initiated stock reservation request.

    Lets sales/marketing staff working in the CRM ask the warehouse team to hold
    products for them — the same request → warehouse-team-approval flow as the
    ERP, just callable from the CRM. Creates a PENDING reservation, validates
    availability, and notifies the warehouse team.
    """
    from datetime import timedelta

    from django.utils import timezone as tz

    from warehouse_management.models import (
        Inventory, StockReservation, StockReservationInstance, Warehouse,
    )
    from warehouse_management.stock_availability import (
        expire_reservations_for_warehouse, get_reserved_qty,
    )
    from warehouse_management.views import _notify_warehouse_team_of_reservation

    try:
        company_serial_number = request.data["serial_number"]
        staff_id = request.data["staff_id"]
        warehouse_id = request.data.get("warehouse_id", "")
        reservation_description = request.data.get("reservation_description", "")
        expiry_days = int(request.data.get("expiry_days", 7) or 7)
        items = request.data.get("items", [])
        if isinstance(items, str):
            items = json.loads(items or "[]")

        company_profile = CompanyProfile.objects.get(
            company_serial_number=company_serial_number)
        staff_profile = StaffProfile.objects.get(id=int(staff_id))
        department_name = (
            staff_profile.company_department.department_name
            if staff_profile.company_department is not None else ""
        )
        if not ((department_name in ("sales", "marketing")) or check_if_system_administrator(staff_profile)):
            return Response({"message": "You are unauthorized to perform this action"}, status=401)
        if not items:
            return Response({"message": "No products selected for reservation"}, status=406)

        # Resolve the warehouse: explicit if supplied, else the staff branch's first.
        warehouse = None
        if warehouse_id:
            warehouse = Warehouse.objects.filter(id=int(warehouse_id), recycle_bin=False).first()
        if warehouse is None and staff_profile.company_branch is not None:
            warehouse = staff_profile.company_branch.branch_warehouses.filter(recycle_bin=False).first()
        if warehouse is None:
            return Response({"message": "No warehouse available to reserve from"}, status=406)

        expire_reservations_for_warehouse(warehouse)
        # Validate availability up-front so we never create a partial request.
        for item in items:
            product = Product.objects.get(id=int(item["product_id"]))
            requested = float(item["quantity"])
            try:
                inventory = Inventory.objects.get(product=product, warehouse=warehouse)
                available = max(0.0, float(inventory.quantity) - get_reserved_qty(product, warehouse))
            except Inventory.DoesNotExist:
                return Response({"message": f"No inventory for '{product.product_name}' in {warehouse.warehouse_name}."}, status=406)
            if requested > available:
                return Response({
                    "message": (
                        f"Insufficient stock for '{product.product_name}'. "
                        f"Available: {available}, Requested: {requested}"
                    )
                }, status=406)

        reservation = StockReservation.objects.create(
            warehouse=warehouse,
            reservation_description=(
                reservation_description
                or f"CRM reservation request by {staff_profile.first_name} {staff_profile.last_name}"),
            expiry_date=tz.now() + timedelta(days=expiry_days),
            requested_by=staff_profile,
            created_by=staff_profile,
            last_updated_by=staff_profile,
        )
        for item in items:
            product = Product.objects.get(id=int(item["product_id"]))
            StockReservationInstance.objects.create(
                stock_reservation=reservation,
                product=product,
                quantity_requested=str(item["quantity"]),
            )
        try:
            _notify_warehouse_team_of_reservation(
                reservation, company_profile, staff_profile, len(items))
        except Exception as notify_error:
            print(notify_error)
        try:
            notify_crm_stock([int(i["product_id"]) for i in items])
        except Exception:
            pass

        return Response({
            "message": f"Reservation {reservation.reservation_number} submitted to the warehouse team",
            "reservation_number": reservation.reservation_number,
        }, status=200)
    except Exception as e:
        print(e)
        return Response({"message": "Error creating stock reservation"}, status=500)


@api_view(['POST'])
def get_stock_reservations_crm(request):
    """Return reservation requests raised by a CRM staff member, with status, so
    the CRM can show whether the warehouse team has approved/rejected them."""
    from warehouse_management.models import StockReservation
    from warehouse_management.stock_availability import expire_reservations_for_warehouse

    target_timezone = pytz.timezone('Africa/Nairobi')
    date_format = '%d/%m/%Y, %H:%M'
    payload = {}
    reservation_list = []
    try:
        staff_id = request.data["staff_id"]
        status_filter = request.data.get("status", "all")
        staff_profile = StaffProfile.objects.get(id=int(staff_id))

        qs = StockReservation.objects.filter(
            requested_by=staff_profile, recycle_bin=False).order_by("-id")
        if status_filter and status_filter != "all":
            qs = qs.filter(status=status_filter)

        for res in qs[:200]:
            if res.warehouse is not None:
                expire_reservations_for_warehouse(res.warehouse)
            res.refresh_from_db()
            items = []
            for inst in res.reservation_instances.all():
                items.append({
                    "product_id": str(inst.product.id) if inst.product else "",
                    "product_name": inst.product.product_name if inst.product else "",
                    "unit_of_measurement": inst.product.unit_of_measurement if inst.product else "",
                    "quantity_requested": inst.quantity_requested,
                })
            reservation_list.append({
                "reservation_id": str(res.id),
                "reservation_number": res.reservation_number,
                "reservation_description": res.reservation_description,
                "status": res.status,
                "rejection_reason": res.rejection_reason,
                "warehouse_name": res.warehouse.warehouse_name if res.warehouse else "",
                "expiry_date": datetime.strftime(res.expiry_date.astimezone(target_timezone), date_format) if res.expiry_date else "",
                "created_on": datetime.strftime(res.created_on.astimezone(target_timezone), date_format) if res.created_on else "",
                "items": items,
            })
        payload["reservation_list"] = reservation_list
        return Response({"message": "true", "payload": payload}, status=200)
    except Exception as e:
        print(e)
        return Response({"message": "false", "payload": payload}, status=500)
