from typing import Type
from sqlalchemy.ext.declarative import DeclarativeMeta
from sqlalchemy import Column, Date, Float, BigInteger, Integer, String, Text


# テーブル名を指定して動的にモデルクラスを作成　DeclarativeMetaを継承した型のみ許可
def create_stock_model(
    table_name: str, Base: Type[DeclarativeMeta]
) -> Type[DeclarativeMeta]:
    """
    指定したテーブル名をもとに、SQLAlchemyの動的なモデルクラスを生成します。

    Args:
        table_name (str): モデルに対応させるデータベースのテーブル名。
        Base (DeclarativeMeta): SQLAlchemyのBaseクラス。

    Returns:
        Type (DeclarativeMeta): 動的に生成されたSQLAlchemyモデルクラス。
    """
    # クラス名をテーブル名に基づいて一意にする
    class_name = f"{table_name}Model"

    if table_name in Base.metadata.tables:
        # Base 内に登録されたクラス
        for cls in Base.registry._class_registry.values():
            if hasattr(cls, "__tablename__") and cls.__tablename__ == table_name:
                return cls

    # モデルクラスの定義
    StockModel = type(
        class_name,
        (Base,),
        {
            "__tablename__": table_name,
            "__table_args__": {"extend_existing": True},
            "date": Column(Date, primary_key=True),  # 日付をプライマリキーに設定
            "open": Column(Float),
            "high": Column(Float),
            "low": Column(Float),
            "close": Column(Float),
            "volume": Column(BigInteger),  # BIGINT 型を使用
            "ma5": Column(Float),  # 5日移動平均
            "ma25": Column(Float),  # 25日移動平均
            "ma75": Column(Float),  # 75日移動平均
            "upper2": Column(Float),  # ボリンジャーバンド　 +2σ
            "lower2": Column(Float),  # ボリンジャーバンド -2σ
            "macd": Column(Float),  # MACD
            "macd_signal": Column(Float),  # Signal
            "hist": Column(Float),  # ヒストグラム
            "rsi14": Column(Float),  # RSI14
            "rsi28": Column(Float),  # RSI28
            "rci9": Column(Float),  # RCI9
            "rci26": Column(Float),  # RCI26
            "__repr__": lambda self: f"<{class_name}(date={self.date}, close={self.close})>",
        },
    )

    # 定義したモデルクラスを返却
    return StockModel


# Stock モデルクラスを取得
def get_stock_class(Base: Type[DeclarativeMeta]) -> Type[DeclarativeMeta]:
    """
    指定したテーブル名をもとに、SQLAlchemyの動的なモデルクラスを生成します。

    Args:
        table_name (str): モデルに対応させるデータベースのテーブル名。
        Base (Type[T]): SQLAlchemyのBaseクラス。

    Returns:
        Type[T]: 動的に生成されたSQLAlchemyモデルクラス。
    """

    class Stock(Base):
        __tablename__ = "stocks"

        # id: 主キーでオートインクリメントを有効
        id = Column(Integer, primary_key=True, autoincrement=True)

        # code: ４文字以内でNULLと重複を許可しない
        code = Column(String(4), unique=True, nullable=False)

        # name: 32文字以内でNULLを許可しない
        name = Column(String(32), nullable=False)

        # memo: テキストでNULLを許可
        memo = Column(Text, nullable=True, default="")

        def __repr__(self) -> str:
            return f"<Stock(id={self.id}, code='{self.code}', name='{self.name}')>"

    return Stock
