import yaml
import sys
import os
import shutil
import tempfile
import gc
import time
from sign_pdf import PDFSigner
from win_signer import select_signer
from win_file_picker import get_open_file_native

# Hỗ trợ hiển thị Tiếng Việt trên Windows Console
if sys.platform == "win32":
    sys.stdout.reconfigure(encoding='utf-8')
    sys.stdin.reconfigure(encoding='utf-8')


def load_config():
    config_path = r"d:/ProjectAI/ProjectSign/sign.yaml"
    if os.path.exists(config_path):
        with open(config_path, 'r', encoding='utf-8') as f:
            return yaml.safe_load(f)
    return {}


def main():
    print("--- CHƯƠNG TRÌNH KÝ SỐ TỰ ĐỘNG ---")

    config = load_config()

    # Tạo thư mục đầu ra nếu chưa có
    output_dir = r"d:/ProjectAI/ProjectSign/output"
    os.makedirs(output_dir, exist_ok=True)

    # 1. Chọn tệp PDF bằng giao diện Windows (Native)
    print("\n--- Đang mở bảng chọn tệp PDF ---")
    file_path = get_open_file_native(
        title="Chọn tệp PDF cần ký",
        initial_dir=os.path.join(os.getcwd(), "input")
    )

    if not file_path:
        print("Lỗi: Bạn chưa chọn tệp PDF nào.")
        return

    print(f"Đã chọn tệp: {os.path.basename(file_path)}")

    # 2. Nhập các từ khóa cần ký
    print("\n--- CẤU HÌNH KÝ SỐ ---")
    kw_input = input(
        "Nhập các từ khóa cần ký (ví dụ: 'Bên A, Bên B' - để trống nếu chỉ ký một chỗ mặc định): "
    ).strip()

    keywords = [k.strip() for k in kw_input.split(',')] if kw_input else ["Bên A"]
    print(f"Sẽ ký {len(keywords)} chữ ký: {keywords}")

    # Đường dẫn đầu vào / đầu ra
    current_input = os.path.abspath(file_path)
    base_name = os.path.basename(file_path)
    if not base_name.startswith("signed_"):
        base_name = f"signed_{base_name}"
    final_output = os.path.join(output_dir, base_name)
    temp_files = []

    # Đọc cấu hình Timestamp
    ts_cfg = config.get('signing', {}).get('timestamp', {})
    ts_url = None
    if ts_cfg.get('enabled', False):
        ts_url = ts_cfg.get('url', 'http://timestamp.digicert.com').strip() or None
        if ts_url:
            print(f"\n🕐 LTV Timestamp: BẬT → {ts_url}")

    # Hỏi lựa chọn hiển thị logo một lần
    print("\n🖌️  TÙY CHỌN HIỂN THỊ CHỮ KÝ")
    logo_choice = input("Bạn có muốn chèn hình ảnh logo vào chữ ký không? (y/n) [Enter=y]: ").strip().lower()
    global_use_logo = logo_choice not in ("n", "no", "0", "false")

    try:
        for i, kw in enumerate(keywords):
            print(f"\n>>> THỰC HIỆN KÝ VỊ TRÍ [{i+1}/{len(keywords)}]: '{kw}'")
            print(f"🔔 Vui lòng cắm USB Token của '{kw}' vào máy tính.")

            # Chọn chứng chỉ qua UI Windows
            print(f"--- Đang mở bảng chọn chứng chỉ cho '{kw}' ---")
            signer_win = select_signer()

            if not signer_win:
                print(f"Cảnh báo: Bạn đã hủy ký ở vị trí '{kw}'.")
                continue

            # Tự động dùng TSA của CA tương ứng với USB Token
            # Ưu tiên: tsa_url từ cert (tự detect) → fallback config YAML
            effective_ts_url = getattr(signer_win, 'tsa_url', '') or ts_url
            if effective_ts_url and effective_ts_url != ts_url:
                print(f"🕐 TSA tự động nhận diện từ CA: {effective_ts_url}")
            elif effective_ts_url:
                print(f"🕐 Dùng TSA từ config: {effective_ts_url}")
            else:
                print("⚠️  Không tìm thấy TSA phù hợp — bỏ qua timestamp.")

            # Tạo file tạm mới cho bước này (tránh lock file của bước trước)
            fd, step_temp_path = tempfile.mkstemp(suffix=".pdf", prefix=f"signing_step{i+1}_")
            os.close(fd)
            temp_files.append(step_temp_path)

            print(f"Đang thực hiện ký{' + nhúng timestamp LTV' if effective_ts_url else ''}...")

            try:
                while True:
                    try:
                        pdf_signer_engine = PDFSigner(None, None)
                        pdf_signer_engine.sign_pdf_native(
                            current_input,
                            step_temp_path,
                            keyword=kw,
                            signer=signer_win,
                            offsets=(-45, -15),
                            ts_url=effective_ts_url,   # ← TSA từ cert của USB token
                            use_logo=global_use_logo,
                        )

                        # Chỉ cập nhật current_input sau khi ký thành công
                        current_input = step_temp_path
                        print(f"✅ Đã ký thành công cho '{kw}'" + (" (có LTV timestamp)" if ts_url else "") + ".")
                        break

                    except Exception as e:
                        error_msg = str(e)
                        if any(code in error_msg for code in ("0x80090016", "0x80090020", "THIẾU THIẾT BỊ")):
                            print(f"\n❌ LỖI PHẦN CỨNG: {error_msg}")

                            import ctypes
                            MB_RETRYCANCEL = 0x00000005
                            MB_ICONWARNING  = 0x00000030
                            IDRETRY = 4

                            res = ctypes.windll.user32.MessageBoxW(
                                0,
                                f"LỖI: {error_msg}\n\nVui lòng cắm USB Token của '{kw}' vào máy tính rồi nhấn [Retry].",
                                "Yêu cầu USB Token",
                                MB_RETRYCANCEL | MB_ICONWARNING
                            )

                            if res == IDRETRY:
                                print(f"🔄 Đang kết nối lại với Token '{kw}'...")
                                continue
                            else:
                                print(f"⚠️ Đã bỏ qua vị trí '{kw}'.")
                                break
                        else:
                            print(f"\n❌ Lỗi không mong muốn: {error_msg}")
                            import traceback
                            traceback.print_exc()
                            break

            finally:
                # Giải phóng tài nguyên PKCS#11/CNG trước bước tiếp theo
                _s = signer_win
                del signer_win
                del _s
                gc.collect()
                time.sleep(0.5)   # Chờ driver USB giải phóng lock

        # Sau khi ký xong tất cả, copy kết quả cuối vào đích
        abs_path = None
        try:
            shutil.copy2(current_input, final_output)
            abs_path = os.path.abspath(final_output)
            print(f"\n✅ HOÀN TẤT QUY TRÌNH KÝ!")
            print(f"📍 Tệp kết quả: {abs_path}")
        except PermissionError:
            abs_path = os.path.abspath(current_input)
            print(f"\n⚠️ CẢNH BÁO: Không thể ghi đè '{final_output}' (đang được mở bởi ứng dụng khác).")
            print(f"📍 Tệp tạm tại: {abs_path}")
        except Exception as e:
            abs_path = os.path.abspath(current_input)
            print(f"\n❌ Lỗi khi lưu: {e}")
            print(f"📍 Tệp tạm tại: {abs_path}")

        # Mở thư mục chứa kết quả
        if abs_path:
            try:
                os.startfile(os.path.dirname(abs_path))
            except Exception:
                pass

        # Dọn file tạm (giữ lại file cuối nếu copy thất bại)
        for tf in temp_files:
            if tf != current_input:
                try:
                    os.remove(tf)
                except Exception:
                    pass

    except Exception:
        print(f"\n❌ Lỗi nghiêm trọng:")
        import traceback
        traceback.print_exc()
    finally:
        print("\n--- Chương trình kết thúc ---")


if __name__ == "__main__":
    main()
