from odoo import api, fields, models, _
import logging
from datetime import date,datetime
from math import isnan
import io
import xlsxwriter
from odoo.tools.misc import xlsxwriter
import base64
_logger = logging.getLogger(__name__)

class SOS_Quote_Generation(models.Model):
    _name = 'sos_quote_generation'
    _description = 'Quote Generation'
    _rec_name = 'plan_ref_no'

    plan_ref_no = fields.Char(
        readonly=True, required=True, string='Plan ID'
    )
    line_ids = fields.One2many('sos_quote_generation_line', 'plan_id', string='Lines', ondelete='cascade')
    def action_export(self):
        output = io.BytesIO()
        workbook = xlsxwriter.Workbook(output, {'in_memory': True})

        headers = {
            'material_name' : 'Material Name',
            'required_qty': 'Required Quantity',
            'status': 'Status',
        }  
        
        self._write_sheet(workbook, 'Materials', self.line_ids, headers)
        workbook.close()
        output.seek(0)

        attachment = self.env['ir.attachment'].create({
            'name': f'{self.plan_ref_no}_Export.xlsx',
            'type': 'binary',
            'datas': base64.b64encode(output.read()),
            'res_model': self._name,
            'res_id': self.id,
            'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        })

        return {
            'type': 'ir.actions.act_url',
            'url': f'/web/content/{attachment.id}?download=true',
            'target': 'self',
        }

    def _write_sheet(self, workbook, sheet_name, line_records, headers):
        """Write data to each sheet based on specified fields and custom headers."""
        worksheet = workbook.add_worksheet(sheet_name)
        for col, header in enumerate(headers.values()):
            worksheet.write(0, col, header)

        for row, record in enumerate(line_records, start=1):
            for col, field in enumerate(headers.keys()):
                value = getattr(record, field, '')
                if isinstance(value, models.Model):
                    worksheet.write(row, col, value.display_name if value else '')
                elif isinstance(value, (fields.Date, fields.Datetime)):
                    worksheet.write(row, col, value.strftime('%Y-%m-%d') if value else '')
                else:
                    worksheet.write(row, col, value)
   
    def action_generate_po(self):
        po_model = self.env['sos_po']
        po_line_model = self.env['sos_po_line']

        supplier_dict = {}
        for record in self.line_ids:
            if record.supplier1_name:
                supplier = record.supplier1_name
                if supplier not in supplier_dict:
                    supplier_dict[supplier] = []
                supplier_dict[supplier].append({
                    'name': record.material_name,
                    'product_qty': record.supplier1_qty,
                    'price_unit': record.supplier1_quoted_price
                })

            if record.supplier2_name:
                supplier = record.supplier2_name
                if supplier not in supplier_dict:
                    supplier_dict[supplier] = []
                supplier_dict[supplier].append({
                    'name': record.material_name,
                    'product_qty': record.supplier2_qty,
                    'price_unit': record.supplier2_quoted_price
                })

            if record.supplier3_name:
                supplier = record.supplier3_name
                if supplier not in supplier_dict:
                    supplier_dict[supplier] = []
                supplier_dict[supplier].append({
                    'name': record.material_name,
                    'product_qty': record.supplier3_qty,
                    'price_unit': record.supplier3_quoted_price
                })
        for x, y in supplier_dict.items():
            sequence_util = self.env['sos_common_scripts']
            po_no = sequence_util.generate_sequence('sos_po','PO', 'po_no')
            po_record = po_model.create({
                'po_no': po_no, 'po_date': date.today(),'supplier_name': x.id,
                'supplier_gst_no': x.gst_no, 'sarf_no':x.supplier_code,
                'supplier_address': x.address
            })
            for components in y:
                po_line_model.create({
                    'po_id': po_record.id, 'component_id': components['name'].id,'qp':components['name'].qp_no,'hsn_code':components['name'].hsn_code,
                    'quantity': components['product_qty'],'unit_price':  components['price_unit'], 'total_price': components['product_qty'] * components['price_unit']
                })
        message = 'Purchase Order(s) successfully generated.'

        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'message': message,
                'type': 'success',
                'sticky': False
            }
        }



    def action_generate_quotation(self):
        supplier_materials = {}
        for item in self.line_ids:
            if item.purchase_type == "supplier":
                for supplier in item.supplier_name:
                    if supplier not in supplier_materials:
                        supplier_materials[supplier] = []
                    supplier_materials[supplier].append({
                        'material_name': item.material_name.id,
                        'required_qty': item.required_qty
                    })

        wizards = []
        for supplier, materials in supplier_materials.items():
            wizard_lines = [(0, 0, {
                'material_name': material['material_name'],
                'required_qty': material['required_qty']
            }) for material in materials]

            wizard = self.env['supplier_quotation_wizard'].create({
                'supplier_id': supplier.id,
                'plan_id': self.id,
                'line_ids': wizard_lines
            })
            wizards.append(wizard.id)
        return {
            'type': 'ir.actions.act_window',
            'name': 'Generate Quotation',
            'view_mode': 'tree,form',
            'res_model': 'supplier_quotation_wizard',
            'domain': [('id', 'in', wizards)],
            'target': 'new',
        }



class SOS_Quote_Generation_Line(models.Model):
    _name = 'sos_quote_generation_line'
    _description = 'Quote Generation Lines'

    plan_id = fields.Many2one('sos_quote_generation', string='Quote Generation', ondelete='cascade')
    
    required_qty = fields.Integer(string='Required Qty')
    purchase_type = fields.Selection([
        ('local', 'Local Purchase'),
        ('supplier', 'Supplier Purchase'),
        ('online', 'Online Purchase')
    ], string='Purchase Type', required=True, default='supplier')
    supplier_name = fields.Many2many('sos_suppliers', string='Supplier', domain="[('id', 'in', suppliers_ids)]")
    suppliers_ids = fields.Many2many('sos_suppliers', compute='_compute_suppliers_ids', store=False)
    is_supplier_name_readonly = fields.Boolean(compute='_compute_is_supplier_name_readonly')
    # Quote Comparison
    material_name = fields.Many2one('sos_material',string="Material Name")
    in_transit_stock_qty = fields.Integer(string="In-Transit Qty",related="material_name.in_transit_stock_qty") 
    supplier1_name = fields.Many2one('sos_suppliers',string="Supplier 1")
    supplier1_quoted_price = fields.Float(string='Price')
    supplier1_qty = fields.Integer(string='Qty')
    supplier2_name = fields.Many2one('sos_suppliers',string="Supplier 2")
    supplier2_quoted_price = fields.Float(string='Price')
    supplier2_qty = fields.Integer(string='Qty')
    supplier3_name = fields.Many2one('sos_suppliers',string="Supplier 3")
    supplier3_quoted_price = fields.Float(string='Price')
    supplier3_qty = fields.Integer(string='Qty')

    final_supplier1_name = fields.Many2one('sos_suppliers',string="Supplier 1")
    final_supplier1_quoted_price = fields.Float(string='Price')
    final_supplier1_qty = fields.Integer(string='Qty')
    best_supplier = fields.Many2one('sos_suppliers', string="Best Deal", compute='_compute_best_supplier', store=True)
    available_suppliers = fields.Many2many('sos_service_providers', compute='_compute_available_suppliers')
    status = fields.Selection(
        [
            ('open', 'Open'),
            ('close', 'Closed')
        ],
        default='open',
        string="Status",
        compute="_compute_from_ir",
        inverse="_set_status",
        store=True
    )

    @api.depends('required_qty', 'in_transit_stock_qty')
    def _compute_from_ir(self):
        for record in self:
            if record.in_transit_stock_qty <= 0: 
                record.status = "close"
            else:
                record.status = "open"

    def _set_status(self):
        for record in self:
            # Custom logic based on user changes
            if record.status == 'close':
                # Perform actions for 'close'
                pass
            elif record.status == 'open':
                # Perform actions for 'open'
                pass

    @api.depends('supplier1_name', 'supplier2_name', 'supplier3_name')
    def _compute_available_suppliers(self):
        for record in self:
            suppliers = []
            if record.supplier1_name:
                suppliers.append(record.supplier1_name.id)
            if record.supplier2_name:
                suppliers.append(record.supplier2_name.id)
            if record.supplier3_name:
                suppliers.append(record.supplier3_name.id)
            record.available_suppliers = [(6, 0, suppliers)]
    @api.onchange('final_supplier1_name')
    def _onchange_final_supplier1_name(self):
        if self.final_supplier1_name:
            # Check which supplier is selected and update price and quantity accordingly
            if self.final_supplier1_name == self.supplier1_name:
                self.final_supplier1_quoted_price = self.supplier1_quoted_price
                self.final_supplier1_qty = self.supplier1_qty
            # elif self.final_supplier1_name == self.supplier2_name:
            #     self.final_supplier1_quoted_price = self.supplier2_quoted_price
            #     self.final_supplier1_qty = self.supplier2_qty
            # elif self.final_supplier1_name == self.supplier3_name:
            #     self.final_supplier1_quoted_price = self.supplier3_quoted_price
            #     self.final_supplier1_qty = self.supplier3_qty
      
    @api.depends('supplier1_quoted_price', 'supplier1_qty', 
                 'supplier2_quoted_price', 'supplier2_qty', 
                 'supplier3_quoted_price', 'supplier3_qty')
    def _compute_best_supplier(self):
        for record in self:
            best_supplier = None
            best_score = float('inf')

            suppliers = [
                (record.supplier1_name, record.supplier1_quoted_price, record.supplier1_qty),
                (record.supplier2_name, record.supplier2_quoted_price, record.supplier2_qty),
                (record.supplier3_name, record.supplier3_quoted_price, record.supplier3_qty)
            ]
            final_supplier_qty = 0
            final_supplier_price = 0
            for supplier, price, qty in suppliers:
                if supplier:
                    score = price / qty if qty else float('inf')
                    if score < best_score:
                        best_score = score
                        best_supplier = supplier
                        final_supplier_qty = qty
                        final_supplier_price = price

            record.best_supplier = best_supplier
            record.final_supplier1_name  = best_supplier
            if best_supplier:
                record.final_supplier1_qty  = final_supplier_qty
                record.final_supplier1_quoted_price  = final_supplier_price


    @api.depends('purchase_type')
    def _compute_is_supplier_name_readonly(self):
        for line in self:
            line.is_supplier_name_readonly = (line.purchase_type == 'local')

    @api.onchange('material_name')
    def _onchange_material_name(self):
        if self.material_name:
            supplier_ids = self.material_name.suppliers.ids
            if supplier_ids:
                self.suppliers_ids = supplier_ids
            else:
                self.suppliers_ids = self.env['sos_suppliers'].search([]).ids
        else:
            self.suppliers_ids = self.env['sos_suppliers'].search([]).ids

    @api.depends('material_name')
    def _compute_suppliers_ids(self):
        for record in self:
            if record.material_name:
                supplier_ids = record.material_name.suppliers.ids
                if supplier_ids:
                    record.suppliers_ids = supplier_ids
                else:
                    record.suppliers_ids = self.env['sos_suppliers'].search([]).ids
            else:
                record.suppliers_ids = self.env['sos_suppliers'].search([]).ids