from datetime import datetime
from typing import Generic, Iterable, Iterator, Literal, TypeVar, get_args
from ksxt.market.base import MarketItemBase, MarketBase
from ksxt.market.db import Base


SCRT_GRP_CLS_CODES = {
    "ST": "주권",
    "MF": "증권투자회사",
    "RT": "부동산투자회사",
    "SC": "선박투자회사",
    "IF": "사회간접자본투융자회사",
    "DR": "주식예탁증서",
    "EW": "ELW",
    "EF": "ETF",
    "SW": "신주인수권증권",
    "SR": "신주인수권증서",
    "BC": "수익증권",
    "FE": "해외ETF",
    "FS": "외국주권",
}

AVLS_SCAL_CLS_CODES = {
    "0": "제외",
    "1": "대",
    "2": "중",
    "3": "소",
}

ETP_PROD_CLS_CODES = {
    "0": "해당없음",
    "1": "투자회사형",
    "2": "수익증권형",
    "3": "ETN",
    "4": "손실제한ETN",
}

SHORT_OVER_CLS_CODES = {
    "0": "해당없음",
    "1": "지정예고",
    "2": "지정",
    "3": "지정연장(해제연기)",
}

MRKT_ALRM_CLS_CODES = {
    "00": "해당없음",
    "01": "투자주의",
    "02": "투자경고",
    "03": "투자위험",
}

FLNG_CLS_CODES = {
    "00": "해당사항없음",
    "01": "권리락",
    "02": "배당락",
    "03": "분배락",
    "04": "권배락",
    "05": "중간배당락",
    "06": "권리중간배당락",
    "99": "기타",
}

FCAM_MOD_CLS_CODES = {
    "00": "해당없음",
    "01": "액면분할",
    "02": "액면병합",
    "99": "기타",
}

ICIC_CLS_CODES = {
    "00": "해당없음",
    "01": "유상증자",
    "02": "무상증자",
    "03": "유무상증자",
    "99": "기타",
}

PRST_CLS_CODES = {
    "0": "해당없음(보통주)",
    "1": "구형우선주",
    "2": "신형우선주",
}


class KrxStockItem(MarketItemBase):
    """국내 주식 정보"""

    excd: str
    """거래소 정보"""
    mksc_shrn_iscd: str
    """단축코드"""
    stnd_iscd: str
    """표준코드"""
    hts_kor_isnm: str
    """한글종목명"""
    scrt_grp_cls_code: Literal["ST", "MF", "RT", "SC", "IF", "DR", "EW", "EF", "SW", "SR", "BC", "FE", "FS"]
    """증권그룹구분코드"""
    curr: str
    """화폐 정보"""
    avls_scal_cls_code: Literal["0", "1", "2", "3"]
    """시가총액 규모 구분 코드 유가"""
    bstp_larg_div_code: str
    """지수 업종 대분류 코드"""
    bstp_medm_div_code: str
    """지수 업종 중분류 코드"""
    bstp_smal_div_code: str
    """지수 업종 소분류 코드"""
    low_current_yn: bool
    """저유동성종목 여부"""
    krx_issu_yn: bool
    """KRX 종목 여부"""
    etp_prod_cls_code: Literal["0", "1", "2", "3"]
    """ETP 상품구분코드"""
    krx100_issu_yn: bool
    """KRX100 종목 여부"""
    krx_car_yn: bool
    """KRX 자동차 여부"""
    krx_smcn_yn: bool
    """KRX 반도체 여부"""
    krx_bio_yn: bool
    """KRX 바이오 여부"""
    krx_bank_yn: bool
    """KRX 은행 여부"""
    etpr_undt_objt_co_yn: bool
    """기업인수목적회사여부"""
    krx_enrg_chms_yn: bool
    """KRX 에너지 화학 여부"""
    krx_stel_yn: bool
    """KRX 철강 여부"""
    short_over_cls_code: Literal["0", "1", "2", "3"]
    """단기과열종목구분코드"""
    krx_medi_cmnc_yn: bool
    """KRX 미디어 통신 여부"""
    krx_cnst_yn: bool
    """KRX 건설 여부"""
    krx_scrt_yn: bool
    """KRX 증권 구분"""
    krx_ship_yn: bool
    """KRX 선박 구분"""
    krx_insu_yn: bool
    """KRX섹터지수 보험여부"""
    krx_trnp_yn: bool
    """KRX섹터지수 운송여부"""
    stck_sdpr: int
    """주식 기준가"""
    frml_mrkt_deal_qty_unit: int
    """정규 시장 매매 수량 단위"""
    ovtm_mrkt_deal_qty_unit: int
    """시간외 시장 매매 수량"""
    trht_yn: bool
    """거래정지 여부"""
    sltr_yn: bool
    """정리매매 여부"""
    mang_issu_yn: bool
    """관리 종목 여부"""
    mrkt_alrm_cls_code: Literal["00", "01", "02", "03"]
    """시장 경고 구분 코드"""
    mrkt_alrm_risk_adnt_yn: bool
    """시장 경고위험 예고 여부"""
    insn_pbnt_yn: bool
    """불성실 공시 여부"""
    byps_lstn_yn: bool
    """우회 상장 여부"""
    flng_cls_code: Literal["00", "01", "02", "03", "04", "05", "06", "99"]
    """락구분 코드"""
    fcam_mod_cls_code: Literal["00", "01", "02", "99"]
    """액면가 변경 구분 코드"""
    icic_cls_code: Literal["00", "01", "02", "03", "99"]
    """증자 구분 코드"""
    marg_rate: int
    """증거금 비율"""
    crdt_able: bool
    """신용주문 가능 여부"""
    crdt_days: int
    """신용기간"""
    prdy_vol: int
    """전일 거래량"""
    stck_fcam: int
    """주식 액면가"""
    stck_lstn_date: datetime
    """주식 상장 일자"""
    lstn_stcn: int
    """상장 주수(천)"""
    cpfn: int
    """자본금"""
    stac_month: int
    """결산 월"""
    po_prc: int
    """공모 가격"""
    prst_cls_code: Literal["0", "1", "2"]
    """우선주 구분 코드"""
    ssts_hot_yn: bool
    """공매도과열종목여부"""
    stange_runup_yn: bool
    """이상급등종목여부"""
    krx300_issu_yn: bool
    """KRX300 종목 여부"""
    sale_account: int
    """매출액"""
    bsop_prfi: int
    """영업이익"""
    op_prfi: int
    """경상이익"""
    thtr_ntin: int
    """당기순이익"""
    roe: float
    """ROE(자기자본이익률)"""
    base_date: datetime
    """기준년월"""
    prdy_avls_scal: int
    """전일기준 시가총액 (억)"""
    grp_code: str
    """그룹사 코드"""
    co_crdt_limt_over_yn: bool
    """회사신용한도초과여부"""
    secu_lend_able_yn: bool
    """담보대출가능여부"""
    stln_able_yn: bool
    """대주가능여부"""

    @property
    def scrt_grp_cls_name(self) -> str:
        return SCRT_GRP_CLS_CODES.get(self.scrt_grp_cls_code, None)

    @property
    def avls_scal_cls_name(self) -> str:
        return AVLS_SCAL_CLS_CODES.get(self.avls_scal_cls_code, None)

    @property
    def etp_prod_cls_name(self) -> str:
        return ETP_PROD_CLS_CODES.get(self.etp_prod_cls_code, None)

    @property
    def short_over_cls_name(self) -> str:
        return SHORT_OVER_CLS_CODES.get(self.short_over_cls_code, None)

    @property
    def mrkt_alrm_cls_name(self) -> str:
        return MRKT_ALRM_CLS_CODES.get(self.mrkt_alrm_cls_code, None)

    @property
    def flng_cls_name(self) -> str:
        return FLNG_CLS_CODES.get(self.flng_cls_code, None)

    @property
    def fcam_mod_cls_name(self) -> str:
        return FCAM_MOD_CLS_CODES.get(self.fcam_mod_cls_code, None)

    @property
    def icic_cls_name(self) -> str:
        return ICIC_CLS_CODES.get(self.icic_cls_code, None)

    @property
    def prst_cls_name(self) -> str:
        return PRST_CLS_CODES.get(self.prst_cls_code, None)

    def __init__(self, data: str):
        super().__init__(data)


t_item = TypeVar("t_item", bound=KrxStockItem)
t_dbitem = TypeVar("t_dbitem", bound=Base)


class KrxStockMarket(Generic[t_item, t_dbitem], MarketBase[t_item, t_dbitem]):
    def search(self, name: str, limit: int = 50) -> Iterable[t_item]:
        """종목을 검색합니다."""
        _, db_type = get_args(self.__orig_bases__[0])  # type: ignore
        return self._search(db_type.hts_kor_isnm, name, limit)  # type: ignore

    def items(self, offset: int = 0, limit: int = 100) -> Iterable[t_item]:
        """종목을 가져옵니다."""
        return super().items(offset, limit)

    def all(self) -> Iterator[t_item]:
        """모든 종목을 가져옵니다."""
        return super().all()  # type: ignore

    def __getitem__(self, code: str) -> t_item:
        """종목을 가져옵니다."""
        _, db_type = get_args(self.__orig_bases__[0])  # type: ignore
        return self._get(db_type.mksc_shrn_iscd, code)
