"""
Trade Proxies for SQLite Storage in FreeExile.
Provides dictionary-like proxies for account stashes, items, and currencies.
"""

from __future__ import annotations
import json
from typing import Any, Optional, Dict, List


class StashItemProxy:
    def __init__(self, engine, original_item):
        super().__setattr__("_engine", engine)
        super().__setattr__("_item", original_item)

    def __getattr__(self, name: str) -> Any:
        return getattr(self._item, name)

    def __setattr__(self, name: str, value: Any) -> None:
        setattr(self._item, name, value)
        self._engine.upsert_item(self._item)


class ItemDictProxy:
    def __init__(self, engine, account_id: str):
        self.engine = engine
        self.account_id = account_id

    def __getitem__(self, key: str):
        item = self.engine.get_item(key)
        if not item or item.owner_account_id != self.account_id:
            raise KeyError(key)
        return StashItemProxy(self.engine, item)

    def __setitem__(self, key: str, item: Any) -> None:
        self.engine.upsert_item(item)

    def __delitem__(self, key: str) -> None:
        self.engine.delete_item(key)

    def __contains__(self, key: str) -> bool:
        item = self.engine.get_item(key)
        return item is not None and item.owner_account_id == self.account_id

    def get(self, key: str, default: Any = None):
        item = self.engine.get_item(key)
        if not item or item.owner_account_id != self.account_id:
            return default
        return StashItemProxy(self.engine, item)

    def __iter__(self):
        cur = self.engine.conn.cursor()
        cur.execute("SELECT item_uuid FROM items WHERE owner_account_id = ?", (self.account_id,))
        for row in cur.fetchall():
            yield row["item_uuid"]

    def keys(self) -> List[str]:
        return list(self)

    def values(self) -> List[Any]:
        cur = self.engine.conn.cursor()
        cur.execute("SELECT item_uuid FROM items WHERE owner_account_id = ?", (self.account_id,))
        return [self[row["item_uuid"]] for row in cur.fetchall()]

    def items(self) -> List[tuple]:
        cur = self.engine.conn.cursor()
        cur.execute("SELECT item_uuid FROM items WHERE owner_account_id = ?", (self.account_id,))
        return [(row["item_uuid"], self[row["item_uuid"]]) for row in cur.fetchall()]

    def __len__(self) -> int:
        cur = self.engine.conn.cursor()
        cur.execute("SELECT COUNT(*) FROM items WHERE owner_account_id = ?", (self.account_id,))
        return cur.fetchone()[0]


class CurrencyDictProxy:
    def __init__(self, engine, account_id: str):
        self.engine = engine
        self.account_id = account_id

    def __getitem__(self, currency_name: str) -> int:
        return self.engine.get_balance(self.account_id, currency_name)

    def __setitem__(self, currency_name: str, amount: int) -> None:
        self.engine.set_balance(self.account_id, currency_name, amount)

    def get(self, currency_name: str, default: int = 0) -> int:
        return self.engine.get_balance(self.account_id, currency_name)

    def _get_bals(self) -> Dict[str, int]:
        cur = self.engine.conn.cursor()
        cur.execute("SELECT balances FROM accounts WHERE account_id = ?", (self.account_id,))
        row = cur.fetchone()
        return json.loads(row["balances"]) if row else {}

    def __iter__(self):
        for k in self._get_bals().keys():
            yield k

    def keys(self) -> List[str]:
        return list(self)

    def values(self) -> List[int]:
        return list(self._get_bals().values())

    def items(self) -> List[tuple]:
        return list(self._get_bals().items())

    def __len__(self) -> int:
        return len(self._get_bals())


class SQLiteAccountStash:
    """A proxy object that interacts with SQLite for AccountStash compatibility."""
    def __init__(self, engine, account_id: str):
        self.engine = engine
        self.account_id = account_id

    @property
    def items(self) -> ItemDictProxy:
        return ItemDictProxy(self.engine, self.account_id)

    @property
    def currencies(self) -> CurrencyDictProxy:
        return CurrencyDictProxy(self.engine, self.account_id)


class SQLiteAccountsProxy:
    """Proxy for InstantBuyoutEngine.accounts."""
    def __init__(self, engine):
        self.engine = engine

    def __getitem__(self, account_id: str) -> SQLiteAccountStash:
        if not self.engine.account_exists(account_id):
            raise KeyError(account_id)
        return SQLiteAccountStash(self.engine, account_id)

    def __setitem__(self, account_id: str, stash: Any) -> None:
        self.engine.ensure_account(account_id)

    def get(self, account_id: str, default: Any = None) -> Optional[SQLiteAccountStash]:
        if self.engine.account_exists(account_id):
            return SQLiteAccountStash(self.engine, account_id)
        return default

    def __iter__(self):
        cur = self.engine.conn.cursor()
        cur.execute("SELECT account_id FROM accounts")
        for row in cur.fetchall():
            yield row["account_id"]

    def keys(self) -> List[str]:
        return list(self)

    def values(self) -> List[SQLiteAccountStash]:
        return [self[k] for k in self]

    def items(self) -> List[tuple]:
        return [(k, self[k]) for k in self]

    def __len__(self) -> int:
        cur = self.engine.conn.cursor()
        cur.execute("SELECT COUNT(*) FROM accounts")
        return cur.fetchone()[0]
