from django.db import models
from authentication.models import User
from authentication.models import ActivityLog
from customer.models import Customer
from leads.models import Lead
from django.utils import timezone
from product.models import Product,SerialNumber
from datetime import timedelta
from supplier.models import Supplier,Supplier_Bill
from django.db.models.signals import post_save,pre_save
from django.dispatch import receiver
import datetime
from django.db.models import Count
import reversion
from django.db.models import Q
import json  
from technician.firebaseManager import sendPush
from fcm_django.models import FCMDevice
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer

class BaseModel(models.Model):
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='%(class)s_created', null=True, blank=True)
    updated_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='%(class)s_updated', null=True, blank=True)
    deleted_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='%(class)s_deleted', null=True, blank=True )

    created_at = models.DateTimeField(auto_now_add=True,null=True)
    updated_at = models.DateTimeField(auto_now=True)
    deleted_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        abstract = True
        
    
    def delete(self, *args, **kwargs):
        self.deleted_at = timezone.now()
        self.save()
        

class Discount(models.Model):
    discount_price = models.IntegerField(default=0,null=True, blank=True)


class GST(models.Model):
    gst_price = models.IntegerField(default=0,null=True, blank=True)


class Quotation(BaseModel):

    CREATED = 0
    SENTED = 1
    ACCEPTED = 2
    CONVERTED_INVOICE = 3
    REJECTED = 4
    APPROVED_ADMIN = 5
    
    STATUS_CHOICES = (
        (CREATED, 'Created'),
        (SENTED, 'Sented'),
        (ACCEPTED, 'Accepted'),
        (CONVERTED_INVOICE, 'Converted Invoice'),
        (REJECTED, 'Rejected'),
        (APPROVED_ADMIN, 'Approved Admin'),
      
    )

    quote_title = models.CharField(max_length=255,null=True)
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, null=True, blank=True, related_name="quotes")
    lead = models.ForeignKey(Lead, on_delete=models.CASCADE, null=True, blank=True, related_name="quotes")
    quote_by = models.ForeignKey(User, on_delete=models.CASCADE,null=True)
    quote_date=models.DateField(null=True)
    subtotal = models.DecimalField(max_digits=10, decimal_places=2)
    discount_type =  models.CharField(max_length=50,null=True)
    discount =  models.DecimalField(max_digits=10, decimal_places=2)
    discount_percent=models.IntegerField(default=0,null=True, blank=True)
    gst = models.DecimalField(max_digits=10, decimal_places=2)
    gst_percent=models.IntegerField(default=0,null=True, blank=True)
    email_to_financial_broker=models.BooleanField(default=False)
    total = models.DecimalField(max_digits=10, decimal_places=2,null=True)
    sent_mail_customer = models.BooleanField(default=False)
    is_trade=models.PositiveSmallIntegerField(default=0)
    manual_quote_pdf = models.FileField(upload_to='manual_quote_pdfs/', blank=True, null=True)
    manual_quote_doc = models.FileField(upload_to='manual_quote_docs/', blank=True, null=True)
    sent_mail_admin = models.BooleanField(default=False) 
    admin_response_mail = models.BooleanField(default=False) 
    quote_send_date = models.DateField(null=True, blank=True)
    reject_reason = models.TextField(null=True, blank=True)
    producttable_page_pdf = models.FileField(upload_to='manual_quote_pdfs/', blank=True, null=True)
    first_page_pdf = models.FileField(upload_to='manual_quote_pdfs/', blank=True, null=True)
    contract_page_pdf = models.FileField(upload_to='manual_quote_pdfs/', blank=True, null=True)
    
    pdf_file = models.FileField(upload_to='quote_pdfs/', blank=True, null=True)
    doc_file = models.FileField(upload_to='quote_docs/', blank=True, null=True)
    is_active = models.BooleanField(default=True)
    status =models.PositiveSmallIntegerField(choices=STATUS_CHOICES,default=0)
    version_number = models.PositiveIntegerField(default=1)
    required_send_to_admin=models.PositiveIntegerField(default=0)
   
    def total_amount(self):
        return "${:,.2f}".format(self.total)

    def soft_delete(self):
     
        self.deleted_at = timezone.now()
        self.is_active = False
        self.save()
        self.items.all().delete()

    def undelete(self):

        self.deleted_at = None
        self.is_active = True
        self.save()

    def __str__(self):
        return f"Quote {self.id} - {self.customer}"
    

    def get_status(self):
         return "Active" if self.is_active else "Inactive"
         
    def latest_version(self):
        quotation_versions=QuotationVersion.objects.filter(original_quote=self.id).count()
        if quotation_versions:
            return quotation_versions+1
        else:
            return 1
            
           
    @property           
    def get_history(self):

        # quote_history1=ActivityLog.objects.filter(new_data__0__fields__quotation = self.id ).order_by('-timestamp')
        # quote_history=list(quote_history1) +  list(ActivityLog.objects.filter(model_name = 'Quotation', instance_id = self.id).order_by('-timestamp'))
        
        quote_history=ActivityLog.objects.filter(Q(model_name = 'Quotation', instance_id = self.id)| Q(new_data__0__fields__quotation = self.id )).order_by('-timestamp')
        
        if quote_history:
            return quote_history
        else:
            return None     

    

class QuotationItem(BaseModel):
    quotation = models.ForeignKey(Quotation, on_delete=models.CASCADE, related_name='items' ,null=True)
    description=models.CharField(max_length=255,null=True)
    product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
    cost_per_unit = models.DecimalField(max_digits=10, decimal_places=2)
    qty = models.IntegerField()
    subtotal = models.DecimalField(max_digits=10, decimal_places=2)
    is_trade_product=models.PositiveSmallIntegerField(default=0)
    trade_product=models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, related_name='trade_product')

    def __str__(self):
        return f"Quote Item {self.id} "

    # @property           
    # def get_trade_product(self):
    #     if self.is_trade_product == 1:
    #         dd(self.trade_product)
    #         trade_product=Product.objects.filter(self.trade_product)
    #         if trade_product:
    #             return trade_product
    #     else:
    #         return None  

class QuotationVersion(BaseModel):
   
    CREATED = 0
    SENTED = 1
    ACCEPTED = 2
    CONVERTED_INVOICE = 3
    REJECTED = 4
    STATUS_CHOICES = (
        (CREATED, 'Created'),
        (SENTED, 'Sented'),
        (ACCEPTED, 'Accepted'),
        (CONVERTED_INVOICE, 'Converted Invoice'),
        (REJECTED, 'Rejected'),
      
    )
    original_quote = models.ForeignKey(Quotation, on_delete=models.CASCADE,null=True)
    quote_title = models.CharField(max_length=255,null=True)
    # customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, null=True, blank=True)
    lead = models.ForeignKey(Lead, on_delete=models.CASCADE, null=True, blank=True)
    quote_by = models.ForeignKey(User, on_delete=models.CASCADE,null=True)
    quote_date=models.DateField(null=True)
    subtotal = models.DecimalField(max_digits=10, decimal_places=2)
    discount_type =  models.CharField(max_length=50,null=True)
    discount =  models.DecimalField(max_digits=10, decimal_places=2)
    discount_percent=models.IntegerField(default=0,null=True, blank=True)
    gst = models.DecimalField(max_digits=10, decimal_places=2)
    gst_percent=models.IntegerField(default=0,null=True, blank=True)
    email_to_financial_broker=models.BooleanField(default=False)
    total = models.DecimalField(max_digits=10, decimal_places=2,null=True)
   
    manual_quote_pdf = models.FileField(upload_to='manual_quote_pdfs/', blank=True, null=True)
    manual_quote_doc = models.FileField(upload_to='manual_quote_docs/', blank=True, null=True)

    pdf_file = models.FileField(upload_to='quote_pdfs/', blank=True, null=True)
    doc_file = models.FileField(upload_to='quote_docs/', blank=True, null=True)
    is_active = models.BooleanField(default=True)
    status =models.PositiveSmallIntegerField(choices=STATUS_CHOICES,default=0)
    version_number = models.PositiveIntegerField(default=0)
    def __str__(self):
        return f"Quote {self.original_quote.id} - Version {self.version_number}"
        
        
        
# class QuotationItemVersion(BaseModel):
#     original_quote_item = models.ForeignKey(QuotationItem, on_delete=models.CASCADE,null=True)
#     version_number = models.PositiveIntegerField(default=0)
#     def __str__(self):
#         return f"Quote {self.original_quote.id} - Version {self.version_number}"


class ContractOfSale(BaseModel):
    content = models.TextField()
    is_active = models.BooleanField(default=True)
    

    def soft_delete(self):
       
        self.is_active = False
        self.deleted_at = timezone.now()
        self.save()

    def undelete(self):
        
        self.is_active = True
        self.deleted_at = None
        self.save()

    def __str__(self):
        return f"Contract of Sale {self.id}"

    class Meta:
        verbose_name_plural = "Contracts of Sale"


class Signature(BaseModel):
    quotation = models.ForeignKey(Quotation, on_delete=models.CASCADE, related_name='signature' ,null=True)
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE,null=True)
    lead = models.ForeignKey(Lead, on_delete=models.CASCADE,null=True)
    email = models.EmailField()
    signature_text = models.CharField(max_length=255)
    signature_image = models.ImageField(upload_to='signatures/')
    terms1_accepted = models.BooleanField(default=False)


    def __str__(self):
        return f"Signature {self.id} - {self.customer}"


class Invoice(BaseModel):
    CREATED = 0
    SENTED = 1
    ACCEPTED = 2
    OPEN=3
    CLOSE=4



    STATUS_CHOICES = (
        (CREATED, 'Created'),
        (SENTED, 'Sented'),
        (ACCEPTED, 'Accepted'),
        (OPEN, 'Open'),
        (CLOSE, 'Close'),
      
    )
    
    
    
    SALES_ORDER=0
    INVOICE=1
    
    
    FLAG_CHOICES=(
        (SALES_ORDER, 'Created'),
        (INVOICE, 'Invoice'),
    
    )
     
    uid=models.TextField(null=True)
    myob_inv_no=models.CharField(max_length=100, null=True)
    sale_uid=models.TextField(null=True)
    quotation = models.ForeignKey(Quotation, on_delete=models.SET_NULL, null=True, blank=True)
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
    mailstatus = models.PositiveSmallIntegerField(choices=STATUS_CHOICES,default=0)
    invoice_date=models.DateField(null=True)
    due_date=models.DateField(null=True)
    discount_type =  models.CharField(max_length=50,null=True)
    po_number=models.CharField(max_length=50, null=True)
    subtotal = models.DecimalField(max_digits=10, decimal_places=2)
    discount = models.DecimalField(max_digits=10, decimal_places=2)
    discount_percent=models.IntegerField(default=0,null=True, blank=True)
    gst = models.DecimalField(max_digits=10, decimal_places=2)
    gst_percent=models.IntegerField(default=0,null=True, blank=True)
    total = models.DecimalField(max_digits=10, decimal_places=2)
    total_paid_amount=models.DecimalField(max_digits=10, decimal_places=2,null=True)
    payable_amount = models.DecimalField(max_digits=10, decimal_places=2)
    is_trade=models.PositiveSmallIntegerField(default=0)
    pdf_file = models.FileField(upload_to='invoice_pdfs/', blank=True, null=True)
    doc_file = models.FileField(upload_to='invoice_docs/', blank=True, null=True)
    myob_invoice_pdf=models.FileField(upload_to='myob_invoice_pdf/', blank=True, null=True)
    is_active = models.BooleanField(default=True)
    status =models.PositiveSmallIntegerField(choices=STATUS_CHOICES,default=0)
    payment_reference_id=models.TextField(null=True,blank=True)
    stripe_id=models.TextField(null=True,blank=True)   
    flag=models.PositiveSmallIntegerField(choices=FLAG_CHOICES,null=True,blank=True)
    comment = models.TextField(null=True, blank=True)
    
    
    def total_amount(self):
        return "${:,.2f}".format(self.total)
    
    def paid_amount(self):
        return "${:,.2f}".format(self.total_paid_amount)
    
    def due_amount(self):
        return "${:,.2f}".format(self.total - self.total_paid_amount)
    
    @property
    def get_supplier(self):
        # Assuming an invoice can have multiple invoice items
        # and we're getting the supplier from the first invoice item
        first_invoice_item = self.invoice_items.first()
        
        if first_invoice_item:
            return first_invoice_item.supplier
        else:
            return None
    @property           
    def get_invoice_payment_records(self):
        # Assuming an invoice can have multiple invoice items
        # and we're getting the supplier from the first invoice item
        invoice_payment_records= self.invoice_payment.filter(invoice__id=self.id).order_by('-paydate')
        
        if invoice_payment_records:
            return invoice_payment_records
        else:
            return None 
    @property           
    def get_invoice_last_payment_record(self):
        # Assuming an invoice can have multiple invoice items
        # and we're getting the supplier from the first invoice item
        invoice_payment_records= self.invoice_payment.filter(invoice__id=self.id).order_by('-paydate')
        
        if invoice_payment_records:
            return invoice_payment_records[0]
        else:
            return None 
            
    def soft_delete(self):
    
        self.deleted_at = timezone.now()
        self.is_active = False
        self.save()
       

    def undelete(self):
        self.deleted_at = None
        self.is_active = True
        self.save()

    def __str__(self):
        return f"Invoice {self.id} - {self.customer}"
    

    def get_status(self):
         return "Active" if self.is_active else "Inactive"
 
            
            
    @property           
    def get_history(self):

        inv_history=ActivityLog.objects.filter(Q(model_name = 'Invoice', instance_id = self.id)| Q(new_data__0__fields__invoice = self.id )).order_by('-timestamp')
        
        if inv_history:
            return inv_history
        else:
                return None     
    
            
            

class InvoiceItem(BaseModel):
    invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, related_name='invoice_items' ,null=True)
    description=models.CharField(max_length=255,null=True)
    product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
    is_trade_product=models.PositiveSmallIntegerField(default=0)
    trade_product=models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, related_name='trade_product_invoice')
    serialnumber = models.ForeignKey(SerialNumber, on_delete=models.SET_NULL, null=True)
    cost_per_unit = models.DecimalField(max_digits=10, decimal_places=2)
    qty = models.IntegerField()
    subtotal = models.DecimalField(max_digits=10, decimal_places=2)
    
    def __str__(self):
        return f"Invoice Item {self.id}"

class InvoicePdf(BaseModel):
    pdf = models.FileField(upload_to='myobinvoice_pdf')


class Confirm_Quote(BaseModel):
    pdf = models.FileField(upload_to='confirm_quote_pdf')


class Customer_Payment(BaseModel):

    uid=models.TextField(null=True)
    invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, related_name='invoice_payment')
    description=models.CharField( max_length=255,null=True)
    bill_number=models.CharField( max_length=50,null=True)
    paydate=models.DateField(auto_now_add=True)
    due_date=models.DateField(null=True)
    payable_amount=models.DecimalField(max_digits=10, decimal_places=2)
    paid_amount=models.DecimalField(max_digits=10, decimal_places=2,null=True)
    due_amount= models.DecimalField(max_digits=10, decimal_places=2,null=True)
    payment_reference_id=models.TextField(null=True,blank=True)
    stripe_id=models.TextField(null=True,blank=True)   
   
   

    def total_amount(self):
        return "${:,.2f}".format(self.total)
    
    def paid_amounts(self):
        return "${:,.2f}".format(self.paid_amount)
    
    def due_amounts(self):
        return "${:,.2f}".format(self.due_amount)




    def __str__(self):
       return f"Amount {self.invoice.total} for Invoice {self.invoice}"
            
       
       
       
    

class Order(BaseModel):
   
    invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, related_name='order_invoice_payment',null=True, blank=True)
   
    order_date=models.DateField(auto_now_add=True,null=True)
    
    
    def __str__(self):
       return f"Order  ID {self.id} "
    

    @property
    def total_job_time(self):
        total_seconds = sum([job.job_duration.total_seconds() for job in self.technician_jobs.all() if job.job_duration])
        
        # Convert total_seconds to hours, minutes, and seconds
        hours, remainder = divmod(total_seconds, 3600)
        minutes, seconds = divmod(remainder, 60)

        return f"{int(hours)}h:{int(minutes)}m:{int(seconds)}s"
        
  
    def get_history(self):
        
       
        if order_history:
            return order_history
        else:
            return None    
            
    @property           
    def get_history(self):

        # order_history1=ActivityLog.objects.filter(new_data__0__fields__order= self.id ).order_by('-timestamp')
        # order_history=list(order_history1) +  list(ActivityLog.objects.filter(model_name = 'Order', instance_id = self.id).order_by('-timestamp'))
        
        order_history=ActivityLog.objects.filter(Q(model_name = 'Order', instance_id = self.id)| Q(new_data__0__fields__order = self.id )).order_by('-timestamp')
        
        if order_history:
            return order_history
        else:
            return None            
            
            
    
    
class Order_Item(BaseModel):
    ORDERED = 0
    SHIPPED = 1
    WATERED = 2
    ARRIVED = 3
    BOOKED_FOR_INSTALL= 4
    NOT_STARTED = 5
    IN_PROGRESS=6
    INSTALLED=7
    SERVICE_REQUESTED=8
    PARTS_REQUESTED=9
    INSTALLATION_COMPLETED=10
    SERVICE_COMPLETED=11
    READY_FOR_INSTALL=12
    

  
 
  
    STATUS_CHOICES = (
        (ORDERED, 'Ordered'),
        (SHIPPED, 'Shipped'),
        (WATERED, 'Watered'),
        (ARRIVED, 'Arrived'),
        (BOOKED_FOR_INSTALL, 'Booked For Install'),
        (NOT_STARTED, 'Not Started'),
        (IN_PROGRESS, 'In Progress'),
        (INSTALLED, 'Installed'),
        (SERVICE_REQUESTED,'Service Requested'),
        (PARTS_REQUESTED,'Parts Requested'),
        (INSTALLATION_COMPLETED,'Installed'), #Installation Completed
        (SERVICE_COMPLETED,'Service Completed'),
        (READY_FOR_INSTALL,'Ready For Install'),
        

    )
    
    INSTALLATION = 1
    SERVICE = 2
    STATUS_CHOICE = (     
        (INSTALLATION,'Installation'),
        (SERVICE,'Service')    
    )
    service_type =models.PositiveSmallIntegerField(choices=STATUS_CHOICE,default=0,null=True)
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='orderset')
    product=models.ForeignKey(Product, on_delete=models.CASCADE, related_name='order_product')
    work_order_pdf = models.FileField(upload_to='workorder_pdfs/', blank=True, null=True)
    order_identifier = models.IntegerField(null=True)
    supplier=models.ForeignKey(Supplier, on_delete=models.CASCADE,null=True, blank=True)
    serial_number=models.ForeignKey(SerialNumber, on_delete=models.CASCADE,null=True, blank=True)
    status =models.PositiveSmallIntegerField(choices=STATUS_CHOICES,default=0,null=True)
    bill = models.ForeignKey(Supplier_Bill, on_delete=models.CASCADE, related_name='order_bill_payment',null=True, blank=True)

    latitude = models.FloatField(null=True)
    longitude = models.FloatField(null=True)    
    view_by_technician=models.BooleanField(default=False)
    installation_complete=models.BooleanField(default=False)
    installed_date = models.DateField(null=True, blank=True)
    warranty_end_date=models.DateField(null=True, blank=True)
    cost_per_unit = models.DecimalField(max_digits=10, decimal_places=2,null=True)
    qty = models.IntegerField(null=True)
    is_trade = models.IntegerField(null=True)
    subtotal = models.DecimalField(max_digits=10, decimal_places=2,null=True)
    is_signature = models.BooleanField(default=False)
    def __str__(self):
       return str(self.id)
    
       
    def save(self, *args, **kwargs):
        if self.installation_complete and self.status == 10:
            # Set installed_date to the current date (extracted from datetime)
            self.installed_date = timezone.now().date()
            self.warranty_end_date = self.installed_date + timedelta(days=2 * 365)
            
       
            
        super().save(*args, **kwargs)
        
 
    @property
    def get_status(self):
       return dict(Order_Item.STATUS_CHOICES).get(self.status, 'Unknown')
 
    @property
    def get_supplier(self):
        # Assuming an invoice can have multiple invoice items
        # and we're getting the supplier from the first invoice item
        return self.supplier

    @property           
    def get_order_history(self):
        # Assuming an invoice can have multiple invoice items
        # and we're getting the supplier from the first invoice item
        order_history= ActivityLog.objects.filter(model_name='Order_Item' , instance_id = self.id ).order_by('id','-timestamp')
        
        if order_history:
            return order_history
        else:
            return None   


    
    

    @property
    def job_times(self):
        job_times_list = []

        for job in Order_Item.technician_jobs.all():  # Assuming related name is 'technician_jobs'
            if job.start_time and job.stop_time:
                job_seconds = (job.stop_time - job.start_time).total_seconds()
                job_times_list.append(job_seconds)

        return job_times_list
        
    @property
    def installation_date(self):
        technician_assigned_order_item = self.order_item.filter(job_type = 1).first()
        if technician_assigned_order_item:
            return technician_assigned_order_item.installation_date
        return None
        
    @property
    def installation_job(self):
        technician_assigned_order_item = self.order_item.filter(job_type = 1).first()
        if technician_assigned_order_item:
            return technician_assigned_order_item
        return None
    @property
    def installation_end_date(self):
        technician_assigned_order_item = self.order_item.filter(job_type = 1).first()
        if technician_assigned_order_item:
            return technician_assigned_order_item.installation_end_date
        return None 
          
    @property
    def installation_time(self):
        technician_assigned_order_item = self.order_item.filter(job_type = 1).first()
        if technician_assigned_order_item:
            return technician_assigned_order_item.installation_time
        return None    
    
    @property
    def get_status_job(self):
        technician_assigned_order_item = Technician_Assigned_Order_Item.objects.filter(order_item__id = self.id,job_type = 1,deleted_at__isnull = True).first()
        if technician_assigned_order_item:
            if str(technician_assigned_order_item.job_completed) == "1":
                return 'Installed'
            else:
                return dict(Order_Item.STATUS_CHOICES).get(self.status, 'Unknown')
        else:
                return dict(Order_Item.STATUS_CHOICES).get(self.status, 'Unknown')
    # @property
    # def get_reattached(self):
    #     technician_assigned_order_item = Technician_Assigned_Order_Item.objects.filter(order_item__id = self.id,job_type = 1,deleted_at__isnull = True).first()
    #     if technician_assigned_order_item:
    #         if technician_assigned_order_item.job_completed == 1:
    #             return 0
    #         else:
    #             if self.status <= 5:
    #                 return 1
    #         return 0
    #     else:
    #             return 1
        
    @property
    def ordered_technician(self):
        technician_assigned_order_item = Technician_Assigned_Order_Item.objects.filter(order_item__id = self.id)
        if technician_assigned_order_item:
            return technician_assigned_order_item[0]
        return None
   
        
    @property
    def technicians(self):
        return User.objects.filter(technicians__order_item=self)
    @property
    def seconday_technicians(self):
        return User.objects.filter(seconday_technicians__order_item=self)


# import json
# import logging    
# from django.db.models import Count        

# logger = logging.getLogger(__name__)

        
class Technician_Assigned_Order_Item(BaseModel):

    INSTALLATION = 1
    SERVICE = 2
    STATUS_CHOICES = (     
        (INSTALLATION,'Installation'),
        (SERVICE,'Service')    
    )
    REQUEST_INSTALLATION = 0
    ACCEPTED_INSTALLATION=1
    IN_PROGRESS_INSTALLATION = 2
    COMPLETED_INSTALLATION = 3
    REQUEST_SERVICE = 4
    ACCEPTED_SERVICE = 5
    IN_PROGRESS_SERVICE = 6
    COMPLETED_SERVICE = 7
    PART_NEEDED  = 8
    PART_RECEIVED = 9  
    WORKING_STATUS_CHOICES=(
        (REQUEST_INSTALLATION, 'Installation Requested'), #Request Installation
        (ACCEPTED_INSTALLATION, 'Installation Requested'), #Accepted Installation
        (IN_PROGRESS_INSTALLATION, 'In Progress'),
        (COMPLETED_INSTALLATION, 'Installed'), #Completed Installation
        (REQUEST_SERVICE, 'Service Requested'), #Request Service
        (ACCEPTED_SERVICE, 'Service Requested'), #Accepted Service
        (IN_PROGRESS_SERVICE, 'In Progress'),
        (COMPLETED_SERVICE, 'Service Completed'), #Completed Service
        
        # (IN_PROGRESS_SERVICE, 'In Progress'),
        # (COMPLETED_SERVICE, 'Completed Service'),
        
        (PART_NEEDED, 'Parts Needed'), #Part Needed
        (PART_RECEIVED, 'Parts Received'), #Part Received
        )
    
    
    
    NOT_STARTED = 0
    IN_PROGRESS=1

    PART_NEEDED=2
    PART_RECEIVED=3
    COMPLETED = 4
  
    JOB_STATUS_CHOICES=(
        (NOT_STARTED, 'Not Started'),
        (IN_PROGRESS, 'In Progress'),

        (PART_NEEDED, 'Parts Needed'), #Part Needed
        (PART_RECEIVED, 'Parts Arrived'), #Part Received
        (COMPLETED, 'Completed'),
        )
    
    
    order_item=models.ForeignKey(Order_Item, on_delete=models.CASCADE, related_name='order_item',null=True)
    technician=models.ForeignKey(User, on_delete=models.CASCADE, related_name='technicians',null=True)
    secondary_technician=models.ForeignKey(User, on_delete=models.CASCADE, related_name='seconday_technicians',null=True)
    replace_technician = models.ForeignKey(User,on_delete=models.SET_NULL,related_name='replace_technician',null=True,blank=True)
    replace_secondary_technician = models.ForeignKey(User,on_delete=models.SET_NULL,related_name='replace_secondary_technicians',null=True,blank=True)
    installation_date=models.DateField(null=True,blank=True)
    installation_end_date=models.DateField(null=True,blank=True)
    installation_time=models.TimeField(null=True)
    service_request_date = models.DateField(null=True, blank=True, auto_now_add=True)
    service_request_time = models.TimeField(null=True, auto_now_add=True)
    booking_date=models.DateField(auto_now_add=True)
    comment=models.CharField(max_length=50,null=True)
    comment_cancel_job=models.CharField(max_length=50,null=True)
    job_type =models.PositiveSmallIntegerField(choices=STATUS_CHOICES,default=1)
    working_status= models.PositiveSmallIntegerField(choices=WORKING_STATUS_CHOICES,default=0,null=True)
    service=models.ForeignKey('service.Service', on_delete=models.CASCADE, related_name='service',null=True)
    status= models.PositiveSmallIntegerField(choices=STATUS_CHOICES,default=0,null=True)
    view_by_technician=models.BooleanField(default=False)
    last_mail_sent_at = models.DateTimeField(null=True, blank=True)
    total_job_time = models.DurationField(blank=True, null=True)
    job_status=models.PositiveSmallIntegerField(choices=JOB_STATUS_CHOICES,default=0,null=True)
    pdf_file = models.FileField(upload_to='checklist_pdfs/', blank=True, null=True)
    job_completed =models.BooleanField(default=False)
    is_signature = models.BooleanField(default=False)
    start_time_timer=models.DateTimeField(null=True)
    stop_time_timer=models.DateTimeField(null=True)
    total_time_timer=models.DurationField(blank=True, null=True)
    job_complete_datetime=models.DateTimeField(null=True)
    customer_signature_required=models.BooleanField(default=False)
    start_stop_job=models.PositiveSmallIntegerField(default=0,null=True)
    is_5_month_reminder_sent = models.BooleanField(default=False)
    is_11_month_reminder_sent = models.BooleanField(default=False)
    is_renewal_active = models.BooleanField(default=True)
    reminder_5_month_datetime = models.DateTimeField(null=True)
    reminder_11_month_datetime = models.DateTimeField(null=True)
    work_order_pdf = models.FileField(upload_to='workorder_pdfs/', blank=True, null=True)
    sign_email_cust=models.BooleanField(default=False)
    sign_email_cust_by=models.ForeignKey(User, on_delete=models.CASCADE, related_name='sign_email_by',null=True)
    # service_type =models.PositiveSmallIntegerField(choices=STATUS_CHOICE,default=1,null=True)
   
    # @property
    # def job_type_display(self):
    #     return dict(STATUS_CHOICES).get(self.job_type, 'Unknown')
       
    @property
    def get_working_status(self):
        return dict(Technician_Assigned_Order_Item.WORKING_STATUS_CHOICES).get(self.working_status, 'Unknown')
    def related_service_request_images(self):
        if self.service:
            image= self.service.service_request.filter(service_request_image__isnull=False).exclude(
            service_request_image=''
        )
            if image:
                return image
            else:
                return None
        else:
            return None
    def related_service_request_videos(self):
        if self.service:
            videos= self.service.service_request.filter(service_request_video__isnull=False).exclude(
                service_request_video=''
            )
            if videos:
                return videos
            else:
                return None
        else:
            return None
    @property    
    def get_serial_number(self):
        if self.serial_number:
            return self.serial_number.serial_number
        else:
            return None
    
    @property    
    def get_chat_count(self):
        from service.models import Chat,ChatImage
        return Chat.objects.filter(job=self).count()
        # chat_image= ChatImage.objects.filter(chat__job=self)
        
     
    # def get_chat_unread_count(self, user):
    #     from service.models import Chat
    
    #     if not user.is_authenticated:
    #         return 0
    
    #     return Chat.objects.filter(
    #         job=self
    #     ).exclude(
    #         sender=user
    #     ).exclude(
    #         reads__user=user
    #     ).count()
    def get_chat_unread_count(self, user):
        from service.models import Chat
        print(f'user print from model {user.id}')
        if not user.is_authenticated:
            return 0
    
        return Chat.objects.filter(
            job=self
        ).exclude(
            sender_id=user.id
        ).exclude(
            reads__user_id=user.id   # 👈 THIS IS SAFE
        ).count()
   
    @property
    def total_job_time(self):
        total_seconds = sum(job.total_job_time.total_seconds() for job in self.technician_jobs.all() if job.total_job_time)
        hours, remainder = divmod(total_seconds, 3600)
        minutes, seconds = divmod(remainder, 60)
        
       
        return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}"
        
    @property
    def total_job_interval_time(self):
        total_seconds = sum(job.total_time_timer.total_seconds() for job in self.technician_jobs_interval.all() if job.total_time_timer)
        hours, remainder = divmod(total_seconds, 3600)
        minutes, seconds = divmod(remainder, 60)
        return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}" 
    @property
    def get_job_interval_time(self):
        total_seconds = self.technician_jobs_interval.all()
        return total_seconds    
        
    @property
    def warranty_date(self):
        if self.order_item.installed_date:
            # Assuming a warranty period of 2 years
            warranty_period = timezone.timedelta(days=365 * 2)
            warranty_date = self.order_item.installed_date + warranty_period
            return warranty_date
    @property
    def get_job_type(self):
        if self.job_type:
            if self.job_type == 1:
                if self.order_item.is_trade == 1:
                    return 'Pickup'
                else:
                    return 'Installation'
            if self.job_type == 2:
                return 'Service'
        return 'null'
    
    def status(self):
         
        if self.order_item.installed_date and self.warranty_date:
            if self.order_item.installed_date <= self.warranty_date:
                return "Warranty"
            else:
               return "Out Of Warranty"
        else:
             return "null" 
   
        
    @property
    def get_combined_data(self):
        from technician.models import CallDetail
        from service.models import Chat,ChatImage
        comments = Technician_Comment.objects.filter(technician_assigend_order_item=self)
        call_logs = CallDetail.objects.filter(assigned_order_item=self)
        chats = Chat.objects.filter(job=self)
        chat_image= ChatImage.objects.filter(chat__job=self)
    
        # Combine the results into a list
        combined_data = list(comments) + list(call_logs) + list(chats) +list(chat_image)
        # dd(combined_data)        dd(combined_data)
        # Sort the combined data by created_at field in ascending order (oldest first)
        combined_data = sorted(combined_data, key=lambda x: getattr(x, 'created_at', None) if hasattr(x, 'created_at') else None)

        return combined_data
    def get_service_signatures(self):
        """
        Return all service signatures linked to this technician order item.
        """
        return self.service_signature.all()

class Technician_Comment(BaseModel):
    technician_assigend_order_item=models.ForeignKey(Technician_Assigned_Order_Item, on_delete=models.CASCADE, related_name='techniciancomment_set',null=True)
    comment=models.CharField(max_length=50,null=True)
    installation_date=models.DateField(null=True,blank=True)
    installation_time=models.TimeField(null=True)

class WorkOrder(models.Model):
    technician_assigend_order_item=models.OneToOneField("Technician_Assigned_Order_Item", on_delete=models.CASCADE, related_name='job_work_order',null=True)
    order_item = models.OneToOneField("Order_Item", on_delete=models.CASCADE, related_name="work_order")
    technician = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
    installation_start_date = models.DateField(null=True, blank=True)
    size = models.CharField(max_length=50, blank=True, null=True)
    note = models.TextField(blank=True, null=True)
    business_hours_from_time = models.CharField(max_length=20, blank=True, null=True)
    business_hours_to_time = models.CharField(max_length=20, blank=True, null=True)
    forklift_available = models.BooleanField(default=False)
    # pdf = models.FileField(upload_to="workorders/", null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    deleted_at = models.DateTimeField(auto_now=False)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='workorders_created', null=True, blank=True)
    updated_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='workorders_updated', null=True, blank=True)
    deleted_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='workorders_deleted', null=True, blank=True)
    address_type = models.CharField(max_length=50, blank=True, null=True)
    suburb = models.TextField(blank=True, null=True)
    street = models.TextField(blank=True, null=True)
    postcode = models.CharField(max_length=50, blank=True, null=True)
    state = models.TextField(blank=True, null=True)
    country = models.TextField(blank=True, null=True)
    def __str__(self):
        return f"WorkOrder for JOB {self.technician_assigend_order_item.id} & OrderItem {self.order_item.id}"
class WorkOrderService(models.Model):
    technician_assigend_order_item=models.OneToOneField("Technician_Assigned_Order_Item", on_delete=models.CASCADE, related_name='service_job_work_order',null=True)
    order_item = models.OneToOneField("Order_Item", on_delete=models.CASCADE, related_name="service_work_order")
    technician = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
    installation_start_date = models.DateField(null=True, blank=True)
    size = models.CharField(max_length=50, blank=True, null=True)
    note_by_admin = models.TextField(blank=True, null=True)
    note_by_customer = models.TextField(blank=True, null=True)
    business_hours_from_time = models.CharField(max_length=20, blank=True, null=True)
    business_hours_to_time = models.CharField(max_length=20, blank=True, null=True)
    forklift_available = models.BooleanField(default=False)
    # pdf = models.FileField(upload_to="workorders/", null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    deleted_at = models.DateTimeField(auto_now=False)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='workorderservice_created', null=True, blank=True)
    updated_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='workorderservice_updated', null=True, blank=True)
    deleted_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='workorderservice_deleted', null=True, blank=True)
    address_type = models.CharField(max_length=50, blank=True, null=True)
    suburb = models.TextField(blank=True, null=True)
    street = models.TextField(blank=True, null=True)
    postcode = models.CharField(max_length=50, blank=True, null=True)
    state = models.TextField(blank=True, null=True)
    country = models.TextField(blank=True, null=True)
    def __str__(self):
        return f"WorkOrder for JOB {self.technician_assigend_order_item.id} & OrderItem {self.order_item.id}"        
@receiver(post_save, sender=Technician_Assigned_Order_Item)
def create_technician_comment(sender, instance, created, **kwargs):
    if created:
        Technician_Comment.objects.create(
            technician_assigend_order_item=instance,
            comment=instance.comment,
            installation_date=instance.installation_date or instance.service_request_date,
            installation_time=instance.installation_time or instance.service_request_time,
            created_by=instance.technician
        )



@receiver(pre_save, sender=Order_Item)
def send_push_notification_on_status_change(sender, instance, **kwargs):
    
    
    if instance.pk is not None:
        # Check if 'status' field has changed
        
       
        original_instance = Order_Item.objects.get(pk=instance.pk)
        if original_instance.status != instance.status:
            push_notification(instance)
      

def push_notification(order_item):
   
    status_mapping = {
        '0': 'Ordered',
        '1': 'Shipped',
        '2': 'Watered',
        '3': 'Arrived',
        '4': 'Booked For Install',
        '5': 'Not Started',
        '6': 'In Progress',
        '7': 'Installed',
        '8': 'Service Requested',
        '9': 'Parts Requested',
        '10': 'Installation Completed',
        '11': 'Service Completed',
    }

    status_code = str(order_item.status)
    # Use get method with a default value if status code is not found
    status = status_mapping.get(status_code, f'Unknown Status Code: {status_code}')
    orderId=order_item.order.id
    ProductName=order_item.product.product_name
    if status != 'Unknown':
        customer = order_item.order.invoice.customer.user.id
        print(status)
        print(customer)
        try:
            get_registration_token = FCMDevice.objects.filter(user_id=customer,active=True)
            for i in get_registration_token:
                dk = sendPush(f'EXCITECH Australia - Order #{orderId} Status', f'Product {ProductName} - {status}', [i.registration_id])
                # dk = sendPush('Product Status Notification', f'EXCITECH Australia - Product Current Status - {status}', [i.registration_id])
        except FCMDevice.DoesNotExist:
            print("FCMDevice not found for the specified conditions. Push notification not sent.")
        except Exception as e:
            print(f"Error sending push notification: {e}")
    
   
# @receiver(post_save, sender=Order)
# def quotation_status_handler(sender, instance,created , **kwargs):
    
#     if  created:
#         print("###################")
#         channel_layer = get_channel_layer()
#         data  = {}
#         data['quotation_id'] = instance.quotation_id
        
    
        
      
#         async_to_sync(channel_layer.group_send)(
#             'quotation_%s' % instance.quotation_id,{
#                 'type': 'quotation_status',
#                 'value': json.dumps(data)
#             }
#         )
            