"""
NSDL Sync scheduled job -- fires the daily trigger call to AWS Phase B's
/sez/deliver-pending endpoint for this site's own client code.

This deliberately does NOT go through the 'Canofy API Call' / 'API
Configuration - Canofy' automatic-dispatch flow (canofy_api_call.py's
after_insert() -> _process_api_call()) -- that controller only ever acts
when "EWAY" appears in the linked API config's name/service_name
(hardcoded in _process_api_call()), so it would silently do nothing for an
NSDL config, and making it dispatch a new integration type would mean
editing that shared controller. Per instruction, nothing already in the
app is to be changed.

Instead, this reuses the two things that ARE genuinely generic:
  - frappe.integrations.utils.make_post_request -- the actual shared
    outbound-HTTP-call helper (this is what e_way_bill_request.py's own
    execute_masters_india_api() calls internally).
  - The 'API Configuration - Canofy' doctype as a config store, read the
    same way e_way_bill_request.py's get_api_config() does (reimplemented
    locally below rather than imported, so this module has zero dependency
    on e-way-bill-specific code).

This file creates the 'NSDL Sync Run' doc itself, BEFORE calling the AWS
endpoint, as the parent record (Build Spec Phase 7) -- Phase B's Lambda
then UPDATES that same doc (never creates a second one) via the
sync_run_name passed through in the request body.

The AWS call is invoked ASYNCHRONOUSLY (the API Gateway integration sets
X-Amz-Invocation-Type: Event) -- Phase B's real work (an NSDL Playwright
login + throttled PDF downloads) routinely runs well past API Gateway's
hard 29s synchronous integration cap, so this call only confirms AWS
accepted the trigger. It does NOT return delivery counts; those arrive
later when Phase B itself updates the NSDL Sync Run doc.

--- One-time setup required per site (MANUAL, not done by this job) ---
1. Create one "API Configuration - Canofy" record named exactly
   NSDL_SYNC_API_CONFIG_NAME below (or change the constant to match
   whatever name you give it), with:
     url                = the deployed SezApiDeliverPendingUrl template
                          output (from `sam deploy`'s Outputs, AWS side)
     api_key_header_key = "x-api-key"
     api_secret          = the real API Gateway key value
                          (aws apigateway get-api-key --api-key <SezApiKeyId>
                          --include-value)
     headers             = {"X-Frappe-Client": "<this site's client_name>"}
                          -- must match the client_name key used in the AWS
                          Secrets Manager CLIENTS block, NOT necessarily this
                          site's display name. Deliberately stored here (the
                          doctype's existing "Additional Static Headers"
                          field) rather than in site_config.json, so the
                          entire integration -- endpoint, credentials, and
                          this site's own identity -- lives in one place a
                          System Manager can edit from the UI, with no
                          server/file access needed.
2. Register this job in hooks.py:
     scheduler_events = {
         "daily": [
             "canofy_tcs.import_documents.nsdl_sync.nsdl_sync_scheduled_job.trigger_nsdl_sync"
         ]
     }
   (adjust the dotted path to wherever this file actually lands in the app --
   "Import_documents" is the module named for the NSDL Sync Run doctype;
   this job would naturally live alongside it.)
"""

from __future__ import annotations

import json

import frappe
from frappe.integrations.utils import make_post_request

NSDL_SYNC_API_CONFIG_NAME = "NSDL SEZ DELIVER PENDING"


def trigger_nsdl_sync():
    """Entry point for hooks.py's scheduler_events. Each site only ever
    triggers its own client's delivery, once per day."""
    try:
        api_config = _get_api_config(NSDL_SYNC_API_CONFIG_NAME)
    except frappe.DoesNotExistError:
        frappe.log_error(
            title="NSDL Sync misconfigured",
            message=f"'{NSDL_SYNC_API_CONFIG_NAME}' API Configuration - Canofy record not found "
            f"-- cannot trigger NSDL sync.",
        )
        return

    # client_name lives in this same record's "Additional Static Headers"
    # field (see module docstring's setup step 1) rather than
    # site_config.json -- one less place to configure, and editable from
    # Frappe's own UI.
    client_name = json.loads(api_config.get("headers") or "{}").get("X-Frappe-Client")
    if not client_name:
        frappe.log_error(
            title="NSDL Sync misconfigured",
            message=f"'{NSDL_SYNC_API_CONFIG_NAME}' API Configuration - Canofy record's Additional "
            f"Static Headers is missing an 'X-Frappe-Client' entry -- cannot trigger NSDL sync.",
        )
        return

    sync_run = frappe.get_doc(
        {
            "doctype": "NSDL Sync Run",
            "run_date": frappe.utils.nowdate(),
            "client_name": client_name,
            "status": "Triggered",
        }
    )
    sync_run.insert(ignore_permissions=True)

    try:
        headers = _get_request_headers(api_config, client_name)

        # Async invocation (X-Amz-Invocation-Type: Event, set by the AWS-side
        # API Gateway mapping) -- this call only confirms AWS ACCEPTED the
        # trigger, it does not carry the actual delivery outcome. Phase B
        # updates this same doc itself once it finishes (see
        # update_audit_doc() on the AWS side); a failure to invoke at all
        # is caught here and separately covered by the DLQ + CloudWatch
        # alarm on the AWS side, per Blueprint SS11.
        make_post_request(
            api_config["url"],
            headers=headers,
            data=json.dumps({"sync_run_name": sync_run.name}),
        )

    except Exception as e:
        error_msg = str(e)
        sync_run.db_set({"status": "Failed", "error_message": error_msg})
        frappe.log_error(title="NSDL Sync trigger failed", message=error_msg)


def _get_api_config(linked_api: str) -> dict:
    """Mirrors the existing get_api_config() convention in
    canofy_tcs/e_way_bill/doctype/e_way_bill_request/e_way_bill_request.py,
    reimplemented locally so this module has no import dependency on
    e-way-bill-specific code."""
    api_doc = frappe.get_doc("API Configuration - Canofy", linked_api)
    return {
        "url": api_doc.url,
        "headers": api_doc.headers,
        "api_key_header_key": api_doc.api_key_header_key,
        "api_secret": api_doc.get_password("api_secret"),
    }


def _get_request_headers(api_config: dict, client_name: str) -> dict:
    headers = json.loads(api_config.get("headers") or "{}")
    headers[api_config.get("api_key_header_key")] = api_config.get("api_secret")
    # Already present in `headers` (that's where trigger_nsdl_sync just read
    # client_name from) -- reassigned explicitly anyway so this function's
    # output is correct even if ever called with a client_name from
    # elsewhere.
    headers["X-Frappe-Client"] = client_name
    headers["Content-Type"] = "application/json"
    return headers
