from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict

import jinja2
import pandas as pd

if TYPE_CHECKING:
    pass


def render_template_from_file(template_path: str, context: Dict[str, Any]) -> str:
    """
    Jinja2를 사용하여 파일 기반 템플릿을 안전하게 렌더링합니다.
    - Context 파라미터 화이트리스트 검증
    - 렌더링된 SQL의 Injection 패턴 검증
    """
    safe_context = _validate_context_params(context)

    template_file = Path(template_path)
    if not template_file.exists():
        raise FileNotFoundError(f"템플릿 파일을 찾을 수 없습니다: {template_path}")

    env = jinja2.Environment(
        loader=jinja2.FileSystemLoader(searchpath=template_file.parent),
        undefined=jinja2.StrictUndefined,
        trim_blocks=True,
        lstrip_blocks=True,
    )

    template = env.get_template(template_file.name)
    rendered_sql = template.render(safe_context)

    _validate_sql_safety(rendered_sql)
    return rendered_sql


def render_template_from_string(sql_template: str, context: Dict[str, Any]) -> str:
    """
    문자열 기반 SQL 템플릿을 안전하게 렌더링합니다. (Batch Inference 전용)
    - Context 파라미터 화이트리스트 검증
    - 렌더링된 SQL의 Injection 패턴 검증
    """
    safe_context = _validate_context_params(context)

    env = jinja2.Environment(
        undefined=jinja2.StrictUndefined,
        trim_blocks=True,
        lstrip_blocks=True,
    )
    template = env.from_string(sql_template)
    rendered_sql = template.render(safe_context)

    _validate_sql_safety(rendered_sql)
    return rendered_sql


def _validate_context_params(context_params: dict) -> dict:
    """
    Context Parameters 값 검증
    변수명은 자유롭게 허용하되, 값의 형식을 검증

    Args:
        context_params: 검증할 컨텍스트 파라미터 딕셔너리

    Returns:
        검증을 통과한 안전한 컨텍스트 딕셔너리

    Raises:
        ValueError: 잘못된 값 형식
    """
    safe_context = {}

    for key, value in context_params.items():
        # 날짜 관련 파라미터는 형식 검증 (date, interval, start, end 등 포함)
        date_keywords = ["date", "interval", "start", "end", "time"]
        is_date_param = any(keyword in key.lower() for keyword in date_keywords)

        if is_date_param and isinstance(value, str):
            try:
                pd.to_datetime(value)  # 날짜 형식 검증
                safe_context[key] = value
            except Exception:
                raise ValueError(f"잘못된 날짜 형식: {key}={value}")
        else:
            safe_context[key] = value

    return safe_context


def _validate_sql_safety(sql: str) -> None:
    """
    SQL 기본 검증 (읽기 전용 쿼리 확인)

    실제 보안은 파라미터 값 검증과 DB 권한으로 확보.
    여기서는 명백한 DDL만 차단.
    """
    import re

    ddl_pattern = r"^\s*(DROP|TRUNCATE|ALTER)\s+"
    if re.search(ddl_pattern, sql.upper(), re.MULTILINE):
        raise ValueError("DDL 명령어(DROP/TRUNCATE/ALTER)는 허용되지 않습니다.")


def is_jinja_template(text: str) -> bool:
    """
    텍스트가 Jinja2 템플릿인지 감지합니다.

    Args:
        text: 검사할 텍스트 문자열

    Returns:
        Jinja2 템플릿 패턴이 포함되어 있으면 True, 아니면 False
    """
    if not text:
        return False

    jinja_patterns = ["{{", "}}", "{%", "%}"]
    return any(pattern in text for pattern in jinja_patterns)
