from __future__ import annotations

import json
import sqlite3
from pathlib import Path

from investly.domain import Observation, Recommendation, SimAction

SCHEMA = """
CREATE TABLE IF NOT EXISTS recommendations(
  id TEXT PRIMARY KEY,
  run_id TEXT NOT NULL,
  market TEXT NOT NULL,
  symbol TEXT NOT NULL,
  strategy TEXT NOT NULL,
  created_at TEXT NOT NULL,
  payload TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS sim_actions(
  id TEXT PRIMARY KEY,
  recommendation_id TEXT NOT NULL,
  created_at TEXT NOT NULL,
  payload TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS observations(
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  recommendation_id TEXT NOT NULL,
  observed_at TEXT NOT NULL,
  payload TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS audit_log(
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  occurred_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
  event_type TEXT NOT NULL,
  entity_id TEXT,
  reason TEXT NOT NULL,
  rule_citations TEXT NOT NULL,
  engine_version TEXT
);
"""


class Ledger:
    def __init__(self, path: str = "investly.db") -> None:
        self.path = Path(path)
        self.conn = sqlite3.connect(self.path)
        self.conn.executescript(SCHEMA)

    def save_recommendation(self, rec: Recommendation) -> None:
        self.conn.execute(
            "INSERT INTO recommendations VALUES (?,?,?,?,?,?,?)",
            (
                rec.recommendation_id,
                rec.run_id,
                rec.market.value,
                rec.symbol,
                rec.strategy.value,
                rec.created_at.isoformat(),
                json.dumps(rec.to_dict()),
            ),
        )
        self.conn.execute(
            "INSERT INTO audit_log(event_type,entity_id,reason,rule_citations,engine_version) VALUES (?,?,?,?,?)",
            (
                "recommendation",
                rec.recommendation_id,
                "recommendation issued",
                json.dumps([citation.__dict__ for citation in rec.rules]),
                rec.engine_version,
            ),
        )
        self.conn.commit()

    def save_action(self, action: SimAction, engine_version: str) -> None:
        payload = {
            **action.__dict__,
            "created_at": action.created_at.isoformat(),
            "rules": [citation.__dict__ for citation in action.rules],
        }
        self.conn.execute(
            "INSERT INTO sim_actions VALUES (?,?,?,?)",
            (action.action_id, action.recommendation_id, action.created_at.isoformat(), json.dumps(payload)),
        )
        self.conn.execute(
            "INSERT INTO audit_log(event_type,entity_id,reason,rule_citations,engine_version) VALUES (?,?,?,?,?)",
            (
                "simulation_action",
                action.action_id,
                action.reason,
                json.dumps([citation.__dict__ for citation in action.rules]),
                engine_version,
            ),
        )
        self.conn.commit()

    def save_observation(self, observation: Observation) -> None:
        payload = {
            **observation.__dict__,
            "observed_at": observation.observed_at.isoformat(),
            "verdict": observation.verdict.value,
        }
        self.conn.execute(
            "INSERT INTO observations(recommendation_id,observed_at,payload) VALUES (?,?,?)",
            (observation.recommendation_id, observation.observed_at.isoformat(), json.dumps(payload)),
        )
        self.conn.commit()
