from __future__ import annotations

import logging
from pathlib import Path

from flask import Blueprint, request, jsonify, Response
from flask_login import login_required

from config import Config
import chardet

file_view_bp = Blueprint("file_view", __name__)


def register_file_view(app):
    """블루프린트 등록"""
    app.register_blueprint(file_view_bp)


def _safe_within(base: Path, target: Path) -> bool:
    """
    target 이 base 디렉터리 내부인지 검사 (경로 탈출 방지)
    """
    try:
        target.resolve().relative_to(base.resolve())
        return True
    except Exception:
        return False


def _decode_bytes(raw: bytes) -> str:
    """
    파일 바이트 → 문자열 디코딩 (감지 → utf-8 → cp949 순서로 시도)
    """
    enc = (chardet.detect(raw).get("encoding") or "utf-8").strip().lower()
    for cand in (enc, "utf-8", "cp949"):
        try:
            return raw.decode(cand)
        except Exception:
            continue
    # 최후의 수단: 손실 허용 디코딩
    return raw.decode("utf-8", errors="replace")


@file_view_bp.route("/view_file", methods=["GET"])
@login_required
def view_file():
    """
    파일 내용을 읽어 반환.
    - /view_file?folder=idrac_info&filename=abc.txt
    - /view_file?folder=backup&date=<백업폴더명>&filename=abc.txt
    - ?raw=1 을 붙이면 text/plain 으로 원문을 반환 (모달 표시용)
    """
    folder = request.args.get("folder", "").strip()
    date = request.args.get("date", "").strip()
    filename = request.args.get("filename", "").strip()
    want_raw = request.args.get("raw")

    if not filename:
        return jsonify({"error": "파일 이름이 없습니다."}), 400

    # 파일명/폴더명은 유니코드 보존. 상위 경로만 제거하여 보안 유지
    safe_name = Path(filename).name

    if folder == "backup":
        base = Path(Config.BACKUP_FOLDER)
        safe_date = Path(date).name if date else ""
        target = (base / safe_date / safe_name).resolve()
    else:
        base = Path(Config.IDRAC_INFO_FOLDER)
        target = (base / safe_name).resolve()

    logging.info(
        "file_view: folder=%s date=%s filename=%s | base=%s | target=%s",
        folder, date, filename, str(base), str(target)
    )

    if not _safe_within(base, target) or not target.is_file():
        logging.warning("file_view: 파일 없음: %s", str(target))
        return jsonify({"error": "파일을 찾을 수 없습니다."}), 404

    try:
        raw = target.read_bytes()
        content = _decode_bytes(raw)

        if want_raw:
            # 텍스트 원문 반환 (모달에서 fetch().text()로 사용)
            return Response(content, mimetype="text/plain; charset=utf-8")

        # JSON으로 감싸서 반환 (기존 사용처 호환)
        return jsonify({"content": content})

    except Exception as e:
        logging.error("file_view: 파일 읽기 실패: %s → %s", str(target), e)
        return jsonify({"error": "파일 열기 중 오류 발생"}), 500