"""Match the registration authority and bank certificate, then link the bank’s LEI to its reported ultimate parent.

Research example. Live observations can change.
"""

from datetime import UTC, datetime
from textwrap import fill

import matplotlib.pyplot as plt
import pandas as pd

AS_OF = datetime.now(UTC).date()
NAVY, BLUE, PINK = "#132244", "#8fb9ff", "#e7a2cc"


def fetch(qj):
    raw = {
        "fdic_bank": qj.domains.call(
            "regulatory.banking.get_institutions", provider="fdic", filters="CERT:628", limit=1
        ),
        "lei_search": qj.domains.call(
            "reference.entities.search_lei_records",
            provider="gleif",
            query="JPMorgan Chase Bank",
            country="US",
            entity_status="ACTIVE",
            registration_status="ISSUED",
            page_size=10,
        ),
    }
    _, record = linked_bank(raw)
    raw["lei_parent"] = qj.domains.call("reference.entities.get_ultimate_parent", provider="gleif", lei=record["id"])
    return raw


def analyze(raw):
    from textwrap import fill

    from matplotlib.patches import FancyBboxPatch

    bank, record = linked_bank(raw)
    parent = payload(raw["lei_parent"])
    if not isinstance(parent, dict) or "attributes" not in parent:
        raise ValueError("No reported ultimate-parent record")
    entity = record["attributes"]["entity"]
    parent_entity = parent["attributes"]["entity"]
    if parent["id"] == record["id"]:
        raise ValueError("The returned parent is the same legal entity")
    rows = [
        {
            "Role": "Regulated bank",
            "Identifier": "FDIC " + str(int(bank["CERT"])),
            "Name": entity["legalName"]["name"],
            "Status": "ACTIVE" if bank["ACTIVE"] == 1 else "INACTIVE",
        },
        {
            "Role": "Bank legal entity",
            "Identifier": record["id"],
            "Name": entity["legalName"]["name"],
            "Status": record["attributes"]["registration"]["status"],
        },
        {
            "Role": "Ultimate parent",
            "Identifier": parent["id"],
            "Name": parent_entity["legalName"]["name"],
            "Status": parent["attributes"]["registration"]["status"],
        },
    ]
    result = pd.DataFrame(rows)
    fig, (ax,) = canvas("Entity identity · bank and ultimate parent", "")
    ax.set_axis_off()
    for index, row in enumerate(rows):
        y = 0.74 - index * 0.31
        box = FancyBboxPatch(
            (0.10, y),
            0.80,
            0.22,
            boxstyle="round,pad=.015,rounding_size=.015",
            transform=ax.transAxes,
            facecolor="#1c3156",
            edgecolor=BLUE if index < 2 else PINK,
            linewidth=1.3,
        )
        ax.add_patch(box)
        ax.text(0.14, y + 0.175, row["Role"], transform=ax.transAxes, color=PINK if index == 2 else BLUE, fontsize=10)
        ax.text(0.14, y + 0.115, fill(row["Name"], width=45), transform=ax.transAxes, fontsize=12, va="center")
        ax.text(
            0.14,
            y + 0.035,
            row["Identifier"] + " · " + row["Status"],
            transform=ax.transAxes,
            fontsize=9,
            color="#afc1dc",
        )
        if index < 2:
            ax.annotate(
                "",
                xy=(0.5, y - 0.075),
                xytext=(0.5, y - 0.02),
                xycoords="axes fraction",
                arrowprops={"arrowstyle": "->", "color": "#afc1dc", "lw": 1.3},
            )
    return result, fig


def payload(response):
    if hasattr(response, "to_dict"):
        response = response.to_dict()
    while isinstance(response, dict):
        if response.get("error") or response.get("error_code") or response.get("success") is False:
            raise ValueError("Provider request failed")
        if "data" in response:
            response = response["data"]
        elif "value" in response:
            response = response["value"]
        else:
            break
    return response


def frame(response, date="date"):
    rows = payload(response)
    if not isinstance(rows, list) or not rows:
        raise ValueError("No provider observations returned")
    result = pd.DataFrame(rows)
    if date:
        result[date] = pd.to_datetime(result[date], utc=True)
        result = result.sort_values(date)
    return result


def canvas(title, ylabel, panels=1):
    plt.rcParams.update(
        {
            "figure.facecolor": NAVY,
            "axes.facecolor": NAVY,
            "savefig.facecolor": NAVY,
            "text.color": "#e9eef8",
            "axes.labelcolor": "#afc1dc",
            "xtick.color": "#afc1dc",
            "ytick.color": "#afc1dc",
            "axes.edgecolor": "#34486b",
            "grid.color": "#34486b",
            "font.size": 10,
            "axes.prop_cycle": plt.cycler(color=[BLUE, PINK, "#ba9dea"]),
        }
    )
    fig, axes = plt.subplots(panels, 1, figsize=(9, 6.1), squeeze=False, layout="constrained")
    fig.suptitle(fill(title, width=58), fontsize=17, x=0.04, ha="left", weight="medium")
    for ax in axes.flat:
        ax.grid(axis="y", alpha=0.45)
        ax.set_axisbelow(True)
        ax.spines[["top", "right"]].set_visible(False)
    axes.flat[0].set_ylabel(ylabel)
    return fig, list(axes.flat)


def run():
    from quantjourney.sdk import QuantJourneyAPI

    qj = QuantJourneyAPI.from_env()
    raw = fetch(qj)
    table, fig = analyze(raw)
    print(table.to_string(index=False))
    fig.savefig(OUTPUT, dpi=180)
    plt.show()


def linked_bank(raw):
    bank = frame(raw["fdic_bank"], date=None).iloc[0]
    certificate = str(int(bank["CERT"]))
    matches = []
    for record in payload(raw["lei_search"]):
        entity = record["attributes"]["entity"]
        if entity.get("registeredAt", {}).get("id") == "RA000744" and str(entity.get("registeredAs")) == certificate:
            matches.append(record)
    if len(matches) != 1:
        raise ValueError("Need one LEI with an exact FDIC authority and certificate match")
    return bank, matches[0]


OUTPUT = "sdk_entity_identity.png"

if __name__ == "__main__":
    run()
