from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from io import BytesIO
from num2words import num2words
import os

# Register the MICR font (relative to this file)
micr_font_path = os.path.join(os.path.dirname(__file__), "micr-encoding/micrenc.ttf")
if not os.path.isfile(micr_font_path):
    raise FileNotFoundError(f"MICR font file not found at {micr_font_path}")
pdfmetrics.registerFont(TTFont("MICR", micr_font_path))


def generate_check_pdf(check):
    """
    Generate a PDF for a Check instance and return bytes.
    """
    buf = BytesIO()
    c = canvas.Canvas(buf, pagesize=letter)
    width, height = letter

    # Bank info
    bank = check.bank_account
    bank_name = bank.institution_name
    bank_street_1 = bank.street_1
    bank_street_2 = bank.street_2
    bank_city = bank.city
    bank_phone = bank.phone
    ACH_ROUTING_NUMBER = bank.routing_number
    ACH_ACCOUNT_NUMBER = bank.account_number

    # Payor info (now on BankAccount)
    payor_name = bank.payor_name
    payor_street_1 = bank.payor_street_1
    payor_street_2 = bank.payor_street_2
    payor_city = bank.payor_city
    payor_phone = bank.payor_phone

    # Payee info
    payee = check.payee
    payee_name = payee.name
    payee_street_1 = payee.street_1
    payee_street_2 = payee.street_2
    payee_city = payee.city
    payor_account_number = payee.payor_account_number

    # Check info
    check_number = str(check.check_number)
    amount = f"{check.amount:.2f}"
    amount_split = amount.split(".")
    amount_words = (
        f"***{num2words(amount_split[0]).title()} and {amount_split[1]}/100***"
    )
    memo = check.memo
    invoice = check.invoice
    check_date = check.check_date.strftime("%m/%d/%Y")

    # Margins
    left_margin = 0.25 * 72
    top_margin = height - 0.25 * 72
    right_margin = width - 0.25 * 72
    payee_alignment = left_margin + 70

    micr_line = f"C{ACH_ROUTING_NUMBER}C A{ACH_ACCOUNT_NUMBER}A {check_number}D"

    # === Payor Information ===
    c.setFont("Helvetica-Bold", 15)
    c.drawString(left_margin, top_margin - 10, payor_name)
    c.setFont("Helvetica", 10)
    payer_line_change = 12
    payor_address_y = top_margin - 22
    if payor_street_1:
        c.drawString(left_margin, payor_address_y, payor_street_1)
        payor_address_y -= payer_line_change
    if payor_street_2:
        c.drawString(left_margin, payor_address_y, payor_street_2)
        payor_address_y -= payer_line_change
    if payor_city:
        c.drawString(left_margin, payor_address_y, payor_city)
        payor_address_y -= payer_line_change
    if payor_phone:
        c.drawString(left_margin, payor_address_y, payor_phone)
        payor_address_y -= payer_line_change

    # === Bank Information ===
    bank_address_left_margin = left_margin + 250
    c.setFont("Helvetica-Bold", 10)
    c.drawString(bank_address_left_margin, top_margin - 10, bank_name)
    c.setFont("Helvetica", 8)
    bank_address_y = top_margin - 21
    bank_address_line_change = 10
    if bank_street_1:
        c.drawString(bank_address_left_margin, bank_address_y, bank_street_1)
        bank_address_y -= bank_address_line_change
    if bank_street_2:
        c.drawString(bank_address_left_margin, bank_address_y, bank_street_2)
        bank_address_y -= bank_address_line_change
    if bank_city:
        c.drawString(bank_address_left_margin, bank_address_y, bank_city)
        bank_address_y -= bank_address_line_change
    if bank_phone:
        c.drawString(bank_address_left_margin, bank_address_y, bank_phone)
        bank_address_y -= bank_address_line_change

    # === Pay ===
    c.setFont("Helvetica-Bold", 10)
    c.drawString(left_margin, top_margin - 70, "Pay")
    c.setFont("Helvetica", 10)
    c.drawString(payee_alignment, top_margin - 70, amount_words)

    # === PAY TO THE ORDER OF ===
    c.setFont("Helvetica", 10)
    c.drawString(left_margin, top_margin - 95, "To the")
    c.drawString(left_margin, top_margin - 105, "Order of:")
    c.drawString(payee_alignment, top_margin - 95, payee_name)

    # === PAYEE ADDRESS ===
    address_y = top_margin - 110
    if payee_street_1:
        c.drawString(payee_alignment, address_y, payee_street_1)
        address_y -= 12
    if payee_street_2:
        c.drawString(payee_alignment, address_y, payee_street_2)
        address_y -= 12
    if payee_city:
        c.drawString(payee_alignment, address_y, payee_city)
        address_y -= 12

    # === CHECK NUMBER ===
    c.setFont("Helvetica-Bold", 12)
    c.drawString(right_margin - 35, top_margin - 5, check_number)

    # === DATE FIELD (optional line) ===
    c.line(left_margin + 450, top_margin - 40, right_margin - 10, top_margin - 40)
    c.drawString(left_margin + 450, top_margin - 35, "Date")
    c.setFont("Helvetica", 10)
    c.drawString(left_margin + 485, top_margin - 35, check_date)

    # === AMOUNT BOX ===
    c.rect(left_margin + 450, top_margin - 75, 115, 20)
    c.setFont("Helvetica-Bold", 14)
    c.drawString(left_margin + 465, top_margin - 70, f"***{amount}***")

    # === MEMO / DESCRIPTION ===
    c.line(left_margin, top_margin - 160, left_margin + 250, top_margin - 160)
    c.setFont("Helvetica", 10)
    c.drawString(left_margin, top_margin - 170, "Memo")  # placeholder
    c.drawString(left_margin, top_margin - 155, memo)

    # === SIGNATURE LINE ===
    c.line(left_margin + 375, top_margin - 160, right_margin - 10, top_margin - 160)
    c.setFont("Helvetica", 10)
    c.drawString(left_margin + 375, top_margin - 170, "Signature")

    # === MICR LINE ===
    c.setFont("MICR", 16)
    c.drawString(left_margin + 125, top_margin - 200, micr_line)

    # === Stub 1 Information ===
    c.setFont("Helvetica-Bold", 12)
    stub_1_y = top_margin - 300
    stub_1_y_offset = 25

    c.drawString(left_margin + 25, stub_1_y, f"Check #{check_number}")
    c.drawString(left_margin + 450, stub_1_y, f"${amount}")
    stub_1_y -= stub_1_y_offset * 1.2
    c.setFont("Helvetica", 12)
    c.drawString(left_margin + 25, stub_1_y, payee_name)
    stub_1_y -= stub_1_y_offset * 1.2
    c.drawString(left_margin + 25, stub_1_y, memo)
    c.setFont("Helvetica", 12)
    stub_1_y -= stub_1_y_offset
    if payor_account_number:
        c.drawString(left_margin + 25, stub_1_y, f"Account: {payor_account_number}")
    stub_1_y -= stub_1_y_offset
    if invoice:
        c.drawString(left_margin + 25, stub_1_y, f"Invoice: {invoice}")
    stub_1_y -= stub_1_y_offset * 2
    c.drawString(left_margin + 25, stub_1_y, f"From: {payor_name}")
    c.drawString(left_margin + 450, stub_1_y, check_date)

    # === Stub 2 Information ===
    stub_2_y = top_margin - 600
    stub_2_y_offset = 15
    c.setFont("Helvetica-Bold", 12)
    c.drawString(left_margin + 25, stub_2_y, f"Check #{check_number}")
    c.drawString(left_margin + 450, stub_2_y, f"${amount}")
    stub_2_y -= stub_2_y_offset * 1.5
    c.setFont("Helvetica", 12)
    c.drawString(left_margin + 25, stub_2_y, payee_name)
    stub_2_y -= stub_2_y_offset * 1.5
    c.drawString(left_margin + 25, stub_2_y, memo)
    stub_2_y -= stub_2_y_offset
    if payor_account_number:
        c.drawString(left_margin + 25, stub_2_y, f"Account: {payor_account_number}")
    stub_2_y -= stub_2_y_offset
    if invoice:
        c.drawString(left_margin + 25, stub_2_y, f"Invoice: {invoice}")
        stub_2_y -= stub_2_y_offset
    # Add category if exists
    if hasattr(check, "category") and check.category:
        c.drawString(left_margin + 25, stub_2_y, f"Category: {check.category.name}")
        stub_2_y -= stub_2_y_offset
    # Add tags if exist
    if hasattr(check, "tags") and check.tags.exists():
        tags_str = ", ".join(tag.name for tag in check.tags.all())
        c.drawString(left_margin + 25, stub_2_y, f"Tags: {tags_str}")
        stub_2_y -= stub_2_y_offset
    c.drawString(
        left_margin + 25,
        stub_2_y,
        f"{bank_name} | Checking Account: {ACH_ACCOUNT_NUMBER}",
    )
    stub_2_y -= stub_2_y_offset
    c.drawString(left_margin + 25, stub_2_y, f"From: {payor_name}")
    c.drawString(left_margin + 450, stub_2_y, check_date)

    c.showPage()
    c.save()
    buf.seek(0)
    return buf.read()
    # All old code removed; only generate_check_pdf remains
