#!/usr/bin/env python3
import html
import json
import os
import re
import sys

try:
    import arabic_reshaper
    from bidi.algorithm import get_display
    from reportlab.lib import colors
    from reportlab.lib.enums import TA_CENTER, TA_RIGHT
    from reportlab.lib.pagesizes import A4
    from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
    from reportlab.lib.units import mm
    from reportlab.pdfbase import pdfmetrics
    from reportlab.pdfbase.ttfonts import TTFont
    from reportlab.platypus import LongTable, Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle
except Exception as exc:
    sys.stderr.write(
        "Missing PDF dependencies: %s. Install: pip install -r requirements.txt\n" % exc
    )
    sys.exit(2)


ARABIC_RE = re.compile(r"[\u0600-\u06ff]")


def find_font(bold=False):
    local_name = "NotoKufiArabic-Bold.ttf" if bold else "NotoKufiArabic-Regular.ttf"
    local_font = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", local_name)
    candidates = [
        local_font,
        os.environ.get("BOT_PDF_FONT_BOLD" if bold else "BOT_PDF_FONT", ""),
    ]
    if bold:
        candidates.extend([
            "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
            "/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf",
            "/usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf",
            "/usr/share/fonts/truetype/noto/NotoNaskhArabic-Bold.ttf",
            "/usr/share/fonts/google-noto/NotoNaskhArabic-Bold.ttf",
            "/usr/share/fonts/google-noto/NotoKufiArabic-Bold.ttf",
            "/usr/share/fonts/noto/NotoNaskhArabic-Bold.ttf",
            "/usr/share/fonts/noto/NotoKufiArabic-Bold.ttf",
            r"C:\Windows\Fonts\arialbd.ttf",
        ])
    else:
        candidates.extend([
            "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "/usr/share/fonts/dejavu/DejaVuSans.ttf",
            "/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf",
            "/usr/share/fonts/truetype/noto/NotoNaskhArabic-Regular.ttf",
            "/usr/share/fonts/google-noto/NotoNaskhArabic-Regular.ttf",
            "/usr/share/fonts/google-noto/NotoKufiArabic-Regular.ttf",
            "/usr/share/fonts/noto/NotoNaskhArabic-Regular.ttf",
            "/usr/share/fonts/noto/NotoKufiArabic-Regular.ttf",
            r"C:\Windows\Fonts\arial.ttf",
        ])
    for candidate in candidates:
        if candidate and os.path.isfile(candidate):
            return candidate

    # cPanel distributions do not all use the same font directory layout.
    preferred_names = (
        ["NotoKufiArabic-Bold.ttf", "NotoNaskhArabic-Bold.ttf", "NotoSansArabic-Bold.ttf", "DejaVuSans-Bold.ttf"]
        if bold else
        ["NotoKufiArabic-Regular.ttf", "NotoNaskhArabic-Regular.ttf", "NotoSansArabic-Regular.ttf", "DejaVuSans.ttf"]
    )
    for font_root in ("/usr/share/fonts", "/usr/local/share/fonts"):
        if not os.path.isdir(font_root):
            continue
        matches = {}
        for directory, _, filenames in os.walk(font_root):
            for filename in filenames:
                if filename in preferred_names and filename not in matches:
                    matches[filename] = os.path.join(directory, filename)
        for preferred_name in preferred_names:
            if preferred_name in matches:
                return matches[preferred_name]

    raise RuntimeError(
        "No Arabic TrueType font found. Missing bundled font: %s" % local_font
    )


def rtl(value):
    value = "" if value is None else str(value)
    if ARABIC_RE.search(value):
        return get_display(arabic_reshaper.reshape(value))
    return value


def safe_text(value):
    return html.escape(rtl(value)).replace("\n", "<br/>")


def para(value, style):
    return Paragraph(safe_text(value), style)


def money(value):
    number = float(value or 0)
    formatted = ("%.3f" % number).rstrip("0").rstrip(".")
    integer, dot, fraction = formatted.partition(".")
    integer = format(int(integer or "0"), ",")
    return integer + (dot + fraction if dot else "")


def build_pdf(data, output_path):
    company_name = str(data.get("company_name") or "")
    pdfmetrics.registerFont(TTFont("StatementArabic", find_font(False)))
    pdfmetrics.registerFont(TTFont("StatementArabicBold", find_font(True)))
    styles = getSampleStyleSheet()
    body = ParagraphStyle(
        "StatementBody", parent=styles["Normal"], fontName="StatementArabic",
        fontSize=7.5, leading=10, alignment=TA_RIGHT, textColor=colors.HexColor("#263d4b")
    )
    body_center = ParagraphStyle("StatementCenter", parent=body, alignment=TA_CENTER)
    bold = ParagraphStyle("StatementBold", parent=body, fontName="StatementArabicBold", fontSize=8.2)
    title = ParagraphStyle(
        "StatementTitle", parent=bold, fontSize=17, leading=22,
        alignment=TA_RIGHT, textColor=colors.white
    )
    subtitle = ParagraphStyle(
        "StatementSubtitle", parent=body, fontSize=8.5, leading=12,
        alignment=TA_RIGHT, textColor=colors.HexColor("#d8eef9")
    )
    doc = SimpleDocTemplate(
        output_path, pagesize=A4, rightMargin=12 * mm, leftMargin=12 * mm,
        topMargin=12 * mm, bottomMargin=16 * mm,
        title="Account Statement", author=company_name
    )
    story = []
    center = data["center"]
    currency = data["currency"]
    stats = data["stats"]

    header = Table([
        [para("شركة %s\nكشف مالي تفصيلي" % company_name, subtitle),
         para("كشف حساب " + currency["name"], title)]
    ], colWidths=[50 * mm, 120 * mm], hAlign="RIGHT")
    header.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#608ab6")),
        ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
        ("RIGHTPADDING", (0, 0), (-1, -1), 12),
        ("LEFTPADDING", (0, 0), (-1, -1), 12),
        ("TOPPADDING", (0, 0), (-1, -1), 13),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 13),
        ("BOX", (0, 0), (-1, -1), 0.7, colors.HexColor("#4c769f")),
    ]))
    story.extend([header, Spacer(1, 5 * mm)])

    balance = float(data["current_balance"])
    balance_label = "مدين لنا" if balance >= 0 else "دائن علينا"
    summary_rows = [
        [para("آخر %s يوم" % data["days"], body), para("نوع الكشف", bold), para(center["name"], body), para("اسم المركز", bold)],
        [para(balance_label + " " + money(abs(balance)), body), para("الحساب الحالي", bold), para("حساب " + currency["name"], body), para("الحساب", bold)],
        [para(data["date_to"], body_center), para("إلى تاريخ", bold), para(data["date_from"], body_center), para("من تاريخ", bold)],
        [para(center["box"], body_center), para("رقم الصندوق", bold), para(stats["movement_count"], body_center), para("عدد جميع الحركات", bold)],
        [para(stats["incoming_count"], body_center), para("عدد الحركات الواردة", bold), para(stats["outgoing_count"], body_center), para("عدد الحركات الصادرة", bold)],
        [para(money(stats["incoming_total"]), body_center), para("إجمالي الدائن - علينا", bold), para(money(stats["outgoing_total"]), body_center), para("إجمالي المدين - لنا", bold)],
    ]
    summary = Table(summary_rows, colWidths=[49 * mm, 36 * mm, 53 * mm, 32 * mm], hAlign="RIGHT")
    summary.setStyle(TableStyle([
        ("FONTNAME", (0, 0), (-1, -1), "StatementArabic"),
        ("BACKGROUND", (0, 0), (-1, -1), colors.white),
        ("GRID", (0, 0), (-1, -1), 0.45, colors.HexColor("#d9e3e9")),
        ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
        ("RIGHTPADDING", (0, 0), (-1, -1), 6),
        ("LEFTPADDING", (0, 0), (-1, -1), 6),
        ("TOPPADDING", (0, 0), (-1, -1), 6),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 6),
        ("TEXTCOLOR", (2, 4), (3, 5), colors.HexColor("#2674a4")),
        ("TEXTCOLOR", (0, 4), (1, 5), colors.HexColor("#c64f58")),
    ]))
    story.extend([summary, Spacer(1, 5 * mm)])

    table_rows = [[
        para("الرصيد", bold), para("دائن علينا", bold), para("مدين لنا", bold),
        para("ملاحظات", bold), para("رقم الحركة", bold),
        para("نوع الحركة", bold), para("التاريخ", bold), para("#", bold)
    ]]
    for index, row in enumerate(data.get("transactions", []), 1):
        debit = money(row["amount"]) if row["kind"] == "outgoing" else ""
        credit = money(row["amount"]) if row["kind"] == "incoming" else ""
        table_rows.append([
            para(money(row["balance"]), body_center), para(credit, body_center), para(debit, body_center),
            para(row["notes"], body), para(row["number"], body_center),
            para(row["type"], body), para(row["date"], body_center), para(index, body_center)
        ])
    if len(table_rows) == 1:
        table_rows.append(["", "", "", "", para("لا توجد حركات ضمن الفترة المحددة", body_center), "", "", ""])

    movements = LongTable(
        table_rows, repeatRows=1, colWidths=[21 * mm, 20 * mm, 20 * mm, 47 * mm, 23 * mm, 25 * mm, 27 * mm, 8 * mm],
        hAlign="RIGHT"
    )
    table_style = [
        ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#608ab6")),
        ("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
        ("GRID", (0, 0), (-1, -1), 0.35, colors.HexColor("#d4dee4")),
        ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
        ("RIGHTPADDING", (0, 0), (-1, -1), 3),
        ("LEFTPADDING", (0, 0), (-1, -1), 3),
        ("TOPPADDING", (0, 0), (-1, -1), 4),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 4),
        ("TEXTCOLOR", (2, 1), (2, -1), colors.HexColor("#2674a4")),
        ("TEXTCOLOR", (1, 1), (1, -1), colors.HexColor("#c64f58")),
    ]
    for row_index in range(2, len(table_rows), 2):
        table_style.append(("BACKGROUND", (0, row_index), (-1, row_index), colors.HexColor("#f5f8fa")))
    movements.setStyle(TableStyle(table_style))
    story.extend([movements, Spacer(1, 4 * mm)])

    opening = Table([[
        para(money(data["opening_balance"]) + " " + currency["name"], bold),
        para("الرصيد السابق", bold)
    ]], colWidths=[125 * mm, 45 * mm], hAlign="RIGHT")
    opening.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#edf6fa")),
        ("BOX", (0, 0), (-1, -1), 0.6, colors.HexColor("#b8d5e3")),
        ("RIGHTPADDING", (0, 0), (-1, -1), 8),
        ("TOPPADDING", (0, 0), (-1, -1), 8),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 8),
    ]))
    story.append(opening)

    def page_footer(canvas, document):
        canvas.saveState()
        canvas.setStrokeColor(colors.HexColor("#d8e2e7"))
        canvas.line(12 * mm, 11 * mm, 198 * mm, 11 * mm)
        canvas.setFont("StatementArabic", 7)
        canvas.setFillColor(colors.HexColor("#6f8089"))
        canvas.drawRightString(198 * mm, 7 * mm, rtl("شركة %s - صفحة %s" % (company_name, document.page)))
        canvas.restoreState()

    doc.build(story, onFirstPage=page_footer, onLaterPages=page_footer)


def main():
    if len(sys.argv) != 2:
        sys.stderr.write("Usage: generate_pdf.py OUTPUT.pdf\n")
        return 2
    try:
        payload = json.load(sys.stdin)
        build_pdf(payload, sys.argv[1])
        sys.stdout.write(json.dumps({"ok": True, "path": sys.argv[1]}))
        return 0
    except Exception as exc:
        sys.stderr.write("PDF generation failed: %s\n" % exc)
        return 1


if __name__ == "__main__":
    sys.exit(main())
