import frappe
import json
from datetime import datetime
from frappe.utils.data import flt
from custom_ui.services import DbService, StripeService, PaymentService
from custom_ui.models import PaymentData

@frappe.whitelist(allow_guest=True)
def half_down_stripe_payment(sales_order):
    """Public endpoint for initiating a half-down advance payment for a sales order."""
    if not DbService.exists("Sales Order", sales_order):
        frappe.throw("Sales Order does not exist.")
    so = DbService.get_or_throw("Sales Order", sales_order)
    if not so.requires_half_payment:
        frappe.throw("This sales order does not require a half-down payment.")
    if so.docstatus != 1:
        frappe.throw("Sales Order must be submitted to proceed with payment.")
    if so.custom_halfdown_is_paid or so.advance_paid >= so.custom_halfdown_amount:
        frappe.throw("Half-down payment has already been made for this sales order.")
    stripe_session = StripeService.create_checkout_session(
        company=so.company,
        amount=so.custom_halfdown_amount,
        service=so.custom_project_template,
        order_num=so.name,
        for_advance_payment=True
    )
    frappe.local.response["type"] = "redirect"
    frappe.local.response["location"] = stripe_session.url
    
@frappe.whitelist(allow_guest=True)
def invoice_stripe_payment(sales_invoice):
    """Public endpoint for initiating a full payment for a sales invoice."""
    if not DbService.exists("Sales Invoice", sales_invoice):
        frappe.throw("Sales Invoice does not exist.")
    si = DbService.get_or_throw("Sales Invoice", sales_invoice)
    if si.docstatus != 1:
        frappe.throw("Sales Invoice must be submitted to proceed with payment.")
    if si.outstanding_amount <= 0:
        frappe.throw("This invoice has already been paid.")
    stripe_session = StripeService.create_checkout_session(
        company=si.company,
        amount=si.outstanding_amount,
        service=si.project_template,
        order_num=si.name,
        for_advance_payment=False
    )
    frappe.local.response["type"] = "redirect"
    frappe.local.response["location"] = stripe_session.url

@frappe.whitelist(allow_guest=True)
def stripe_webhook():
    """Endpoint to handle Stripe webhooks."""
    payload = frappe.request.get_data()
    sig_header = frappe.request.headers.get('Stripe-Signature')
    session, metadata = StripeService.get_session_and_metadata(payload, sig_header)
    
    # Validate required metadata
    if not metadata.get("company"):
        raise frappe.ValidationError("Missing required metadata key: company")
    if not metadata.get("payment_type"):
        raise frappe.ValidationError("Missing required metadata key: payment_type")
    
    # Determine reference document based on payment type
    payment_type = metadata.get("payment_type")
    reference_doctype = None
    reference_doc_name = None
    
    if payment_type == "advance":
        reference_doctype = "Sales Order"
        reference_doc_name = metadata.get("sales_order")
        if not reference_doc_name:
            raise frappe.ValidationError("Missing sales_order in metadata for advance payment")
    elif payment_type == "full":
        reference_doctype = "Sales Invoice"
        reference_doc_name = metadata.get("sales_invoice")
        if not reference_doc_name:
            raise frappe.ValidationError("Missing sales_invoice in metadata for full payment")
    else:
        raise frappe.ValidationError(f"Invalid payment type in metadata: {payment_type}")
    
    # Check if payment already exists
    if DbService.exists("Payment Entry", {"reference_no": session.id}):
        raise frappe.ValidationError("Payment Entry already exists for this session.")
    
    amount_paid = flt(session.amount_total) / 100
    
    # Convert Unix timestamp to date string (YYYY-MM-DD)
    reference_date = datetime.fromtimestamp(session.created).strftime('%Y-%m-%d')
    
    # Set Administrator context to create Payment Entry
    frappe.set_user("Administrator")
    
    try:
        pe = PaymentService.create_payment_entry(
            data=PaymentData(
                mode_of_payment="Stripe",
                reference_no=session.id,
                reference_date=reference_date,
                received_amount=amount_paid,
                company=metadata.get("company"),
                reference_doc_name=reference_doc_name
            )
        )
        pe.flags.ignore_permissions = True
        pe.submit()
        frappe.db.commit()
        return "Payment Entry created and submitted successfully."
    finally:
        # Reset to Guest user
        frappe.set_user("Guest")
    
    
    
    
        
    