"""
recon_engine_py — CloudI Python reconciliation engine service.

Receives file content (base64) + config from Elixir MwRecon.EngineClient,
runs the appropriate matcher module, and returns structured match results.

Service path: /+/recon/engine/  (handles any tenant)

cloudi.conf entry:
  [{prefix,        "/+/recon/engine/"},
   {file_path,     "/usr/bin/python3"},
   {args,          "/app/services/recon_engine_py/main.py"},
   {count_process, 2},
   {max_r,         5},
   {max_t,         300},
   {env, [
     {"PYTHONPATH", "/usr/local/lib/cloudi-2.0.7/api/python:/app/services/recon_engine_py"}
   ]}
  ]

Expected request payload (JSON) — TWO shapes:

V2 generic rule-engine (preferred — docs/RECON_GENERIC_RULE_ENGINE_PLAN.md):
  {
    "rule_set":  { ...decoded recon_rule_schema.json document... },
    "templates": { "<template_name>": { ...source template definition... } },
    "files":     { "<template_name>": "<base64 file content>" },
    "config":    { "location_map": {}, "recon_date": "2025-06-09" }
  }

Preview (R4 onboarding):
  { "preview": { "file": "<base64>", "file_format": "xlsx" } }

Response (JSON):
  {
    "status": "ok",
    "data": {
      "matched_rows":     [...],
      "unmatched_rows":   [...],
      "matched_count":    N,
      "unmatched_count":  N,
      "total_count":      N,
      "matched_amount":   0.0,
      "unmatched_amount": 0.0,
      "total_amount":     0.0,
      "location_summary": [...],
      "sheet_matched":    "...",
      "sheet_unmatched":  "..."
    }
  }
"""

import sys
import json
import logging

sys.path.insert(0, "/usr/local/lib/cloudi-2.0.7/api/python/")
sys.path.insert(0, "/app/services/recon_engine_py/")

from cloudi import API, terminate_exception

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] [CloudI:recon_engine_py] %(message)s",
)
logger = logging.getLogger("recon_engine_py")

class ReconEngineService:
    def __init__(self):
        self.__api = API(0)

    def run(self):
        try:
            self.__api.subscribe("+/recon/engine/", self.__handle_request)
            logger.info("recon_engine_py started, subscribing to +/recon/engine/")
            self.__api.poll()
        except terminate_exception:
            logger.info("recon_engine_py terminated cleanly")
        except Exception as e:
            logger.error(f"Service error: {e}", exc_info=True)

    def __handle_request(self, request_type, name, pattern,
                         request_info, request,
                         timeout, priority, trans_id, pid):
        try:
            payload     = json.loads(request)
            info        = json.loads(request_info) if request_info else {}
            trace_id    = info.get("trace_id", "unknown")
            tenant_id   = info.get("tenant_id", "unknown")

            if "preview" in payload:
                # R4 onboarding: template-less header/sample preview
                preview = payload["preview"]
                logger.info(f"Preview request trace_id={trace_id} tenant_id={tenant_id}")
                from engine.preview import preview_file
                result = preview_file(
                    preview.get("file", ""),
                    preview.get("file_format", "xlsx"),
                )
                return json.dumps({"status": "ok", "data": result})

            if "rule_set" in payload:
                # V2 generic rule-engine path
                rule_set = payload["rule_set"]
                logger.info(
                    f"Recon engine V2 request rule_set={rule_set.get('name')} "
                    f"trace_id={trace_id} tenant_id={tenant_id}"
                )
                from engine import pipeline
                result = pipeline.run(
                    rule_set=rule_set,
                    templates=payload.get("templates", {}),
                    files=payload.get("files", {}),
                    context=payload.get("config", {}),
                )
                logger.info(
                    f"Recon V2 complete trace_id={trace_id} "
                    f"stages={result['summary']['stage_count']} "
                    f"matched={result['summary']['matched_count']} "
                    f"unmatched_a={result['summary']['unmatched_a_count']}"
                )
                return json.dumps({"status": "ok", "engine": "v2", "data": result})

            # Legacy per-type payloads were removed at R6 cutover.
            return json.dumps({
                "status": "error",
                "reason": "Unsupported payload: expected 'rule_set' or 'preview' "
                          "(legacy recon_type payloads were removed)",
            })

        except Exception as e:
            logger.error(f"Recon engine error: {e}", exc_info=True)
            return json.dumps({"status": "error", "reason": str(e)})


if __name__ == "__main__":
    assert API.thread_count() == 1, "Single-threaded service required"
    ReconEngineService().run()
