import frappe
from frappe.utils import get_url

class EmailService:
    
    @staticmethod
    def get_customer_email(customer_name: str, doctype: str = "Customer") -> str | None:
        """
        Get the primary email for a customer or lead.
        
        Args:
            customer_name: Name of the Customer or Lead
            doctype: Either "Customer" or "Lead"
            
        Returns:
            Email address if found, None otherwise
        """
        try:
            customer_doc = frappe.get_doc(doctype, customer_name)
            email = None
            
            # Try primary_contact field
            if hasattr(customer_doc, 'primary_contact') and customer_doc.primary_contact:
                try:
                    primary_contact = frappe.get_doc("Contact", customer_doc.primary_contact)
                    email = primary_contact.email_id
                except Exception as e:
                    print(f"Warning: Could not get primary_contact: {str(e)}")
            
            # Fallback to customer_primary_contact
            if not email and hasattr(customer_doc, 'customer_primary_contact') and customer_doc.customer_primary_contact:
                try:
                    primary_contact = frappe.get_doc("Contact", customer_doc.customer_primary_contact)
                    email = primary_contact.email_id
                except Exception as e:
                    print(f"Warning: Could not get customer_primary_contact: {str(e)}")
            
            # Last resort - get any contact linked to this customer/lead
            if not email:
                contact_links = frappe.get_all("Dynamic Link", 
                    filters={
                        "link_doctype": doctype,
                        "link_name": customer_name,
                        "parenttype": "Contact"
                    },
                    pluck="parent"
                )
                if contact_links:
                    try:
                        contact = frappe.get_doc("Contact", contact_links[0])
                        email = contact.email_id
                    except Exception as e:
                        print(f"Warning: Could not get contact from dynamic link: {str(e)}")
            
            return email
            
        except Exception as e:
            print(f"ERROR: Failed to get email for {doctype} {customer_name}: {str(e)}")
            return None
    
    @staticmethod
    def send_templated_email(
        recipients: str | list,
        subject: str,
        template_path: str,
        template_context: dict,
        doctype: str = None,
        docname: str = None,
        cc: str | list = None,
        bcc: str | list = None,
        attachments: list = None
    ) -> bool:
        """
        Send an email using a Jinja2 template.
        
        Args:
            recipients: Email address(es) to send to
            subject: Email subject line
            template_path: Path to the Jinja2 template (relative to app root)
            template_context: Dictionary of variables to pass to template
            doctype: Optional doctype to link email to
            docname: Optional document name to link email to
            cc: Optional CC recipients
            bcc: Optional BCC recipients
            attachments: Optional list of attachments
            
        Returns:
            True if email sent successfully, False otherwise
        """
        try:
            # Render the email template
            message = frappe.render_template(template_path, template_context)
            
            # Prepare sendmail arguments
            email_args = {
                "recipients": recipients,
                "subject": subject,
                "message": message,
            }
            
            if doctype:
                email_args["doctype"] = doctype
            if docname:
                email_args["name"] = docname
            if cc:
                email_args["cc"] = cc
            if bcc:
                email_args["bcc"] = bcc
            if attachments:
                email_args["attachments"] = attachments
            
            # Send email
            frappe.sendmail(**email_args)
            
            print(f"DEBUG: Email sent successfully to {recipients}")
            return True
            
        except Exception as e:
            print(f"ERROR: Failed to send email: {str(e)}")
            frappe.log_error(f"Failed to send email to {recipients}: {str(e)}", "Email Service Error")
            return False
    
    @staticmethod
    def send_downpayment_email(sales_order_name: str) -> bool:
        """
        Send a down payment email for a Sales Order.
        
        Args:
            sales_order_name: Name of the Sales Order
            
        Returns:
            True if email sent successfully, False otherwise
        """
        try:
            doc = frappe.get_doc("Sales Order", sales_order_name)
            
            # Get customer email
            email = EmailService.get_customer_email(doc.customer, "Customer")
            
            if not email:
                print(f"ERROR: No email found for customer {doc.customer}, cannot send down payment email")
                return False
            
            # Prepare template context
            half_down_amount = doc.custom_halfdown_amount or (doc.grand_total / 2)
            base_url = get_url()
            
            template_context = {
                "company_name": doc.company,
                "customer_name": doc.customer_name or doc.customer,
                "sales_order_number": doc.name,
                "total_amount": frappe.utils.fmt_money(half_down_amount, currency=doc.currency),
                "base_url": base_url
            }
            
            # Send email
            template_path = "custom_ui/templates/emails/downpayment.html"
            subject = f"Down Payment Required - {doc.company} - {doc.name}"
            
            return EmailService.send_templated_email(
                recipients=email,
                subject=subject,
                template_path=template_path,
                template_context=template_context,
                doctype="Sales Order",
                docname=doc.name
            )
            
        except Exception as e:
            print(f"ERROR: Failed to send down payment email for {sales_order_name}: {str(e)}")
            frappe.log_error(f"Failed to send down payment email for {sales_order_name}: {str(e)}", "Down Payment Email Error")
            return False
    
    @staticmethod
    def send_invoice_email(sales_invoice_name: str) -> bool:
        """
        Send an invoice email for a Sales Invoice.
        
        Args:
            sales_invoice_name: Name of the Sales Invoice
            
        Returns:
            True if email sent successfully, False otherwise
        """
        try:
            doc = frappe.get_doc("Sales Invoice", sales_invoice_name)
            
            # Get customer email
            email = EmailService.get_customer_email(doc.customer, "Customer")
            
            if not email:
                print(f"ERROR: No email found for customer {doc.customer}, cannot send invoice email")
                return False
            
            # Calculate amounts
            outstanding_amount = doc.outstanding_amount
            paid_amount = doc.grand_total - outstanding_amount
            
            # Get related Sales Order if available
            sales_order = None
            if hasattr(doc, 'items') and doc.items:
                for item in doc.items:
                    if item.sales_order:
                        sales_order = item.sales_order
                        break
            
            # Prepare template context
            base_url = get_url()
            
            template_context = {
                "company_name": doc.company,
                "customer_name": doc.customer_name or doc.customer,
                "invoice_number": doc.name,
                "invoice_date": doc.posting_date,
                "due_date": doc.due_date,
                "grand_total": frappe.utils.fmt_money(doc.grand_total, currency=doc.currency),
                "outstanding_amount": frappe.utils.fmt_money(outstanding_amount, currency=doc.currency),
                "paid_amount": frappe.utils.fmt_money(paid_amount, currency=doc.currency),
                "sales_order": sales_order,
                "base_url": base_url,
                "payment_url": f"{base_url}/api/method/custom_ui.api.public.payments.invoice_stripe_payment?sales_invoice={doc.name}" if outstanding_amount > 0 else None
            }
            
            # Send email
            template_path = "custom_ui/templates/emails/invoice.html"
            subject = f"Invoice {doc.name} - {doc.company}"
            
            return EmailService.send_templated_email(
                recipients=email,
                subject=subject,
                template_path=template_path,
                template_context=template_context,
                doctype="Sales Invoice",
                docname=doc.name
            )
            
        except Exception as e:
            print(f"ERROR: Failed to send invoice email for {sales_invoice_name}: {str(e)}")
            frappe.log_error(f"Failed to send invoice email for {sales_invoice_name}: {str(e)}", "Invoice Email Error")
            return False