import os, sys, argparse, warnings, ctypes
from pathlib import Path
from datetime import datetime

# Attach to the parent process console so print() is visible when launched from a .bat
ctypes.windll.kernel32.AttachConsole(-1)
sys.stdout = open("CONOUT$", "w")
sys.stderr = open("CONOUT$", "w")

# Suppress GDAL FutureWarning
warnings.filterwarnings("ignore", category=FutureWarning, module="osgeo")

# === Environment setup ===
base = Path(__file__).parent
sys.path.insert(0, str(base))
# =========================

import requests
import jwt as pyjwt

from validator.src.packages.processes import DocumentVerification, DocumentValidation
from validator.src.services.validation_packages_service import ValidationPackageService
from validator.src.services.validation_metadata_service import ValidationMetadataService
from validator.src.services.authentification_service import Authentification
from shared.utils import ConfigManager

def is_tester_on_production(email: str, password: str) -> bool:
    """Authenticate against the production server and check is_tester from that token."""
    config = ConfigManager()
    prod_url = config.get_value(section="PROVIDER", key="production")
    auth_path = config.get_value(section="LOGIN", key="auth")
    try:
        resp = requests.post(prod_url + auth_path, json={"email": email, "password": password}, timeout=30)
        if resp.status_code != 200:
            return False
        token = resp.json().get("access", "")
        decoded = pyjwt.decode(token, options={"verify_signature": False}, algorithms=["HS256"])
        return bool(decoded.get("is_tester", False))
    except Exception:
        return False

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("file_path", help="Path to .zip or .gpkg file")
    parser.add_argument("--dev", action="store_true", help="Use development packages instead of public")
    parser.add_argument("--email", help="Account email (optional, uses saved token if omitted)")
    parser.add_argument("--password", help="Account password (optional, uses saved token if omitted)")
    parser.add_argument("--package-version", dest="package_version", help="Validation package version to use (e.g. 3.0.0). Defaults to version detected from the file.")
    parser.add_argument("--output", help="Folder to save the report CSV. Defaults to the Desktop.")
    args = parser.parse_args()

    # === Authenticate ===
    auth = Authentification()
    if args.email and args.password:
        result = auth.login(email=args.email, password=args.password)
        if result is not True:
            print(f"[ERROR] Login failed: {result}")
            sys.exit(1)
        print("[AUTH] Logged in")
    else:
        if not auth.autologin():
            print("[ERROR] Authentication failed. Pass --email and --password or run the validator app to log in first.")
            sys.exit(1)
        print("[AUTH] Token OK")

    if args.dev:
        tester = auth.check_is_tester()
        if not tester:
            print("[ERROR] --dev requires a tester account.")
            sys.exit(1)

    production = not args.dev
    env_label = "production" if production else "development"
    print(f"\n[ENV] {env_label}")

    # === Output folder ===
    if args.output:
        output_folder = Path(args.output)
    else:
        output_folder = Path.home() / "Desktop"
    output_folder.mkdir(parents=True, exist_ok=True)

    # === Load services ===
    packageService = ValidationPackageService()
    metadataService = ValidationMetadataService()

    valid_templates = packageService.get_validation_packages_version(production=production)
    local_packages = packageService.get_local_packages(production=production)
    print(f"[PACKAGES] Local: {local_packages}")

    # === Step 1: Verification ===
    print("\n--- Verification ---")
    verifier = DocumentVerification()
    verification_result_holder = {}

    def verification_callback(complete, message, verification_result):
        print(f"  {'[DONE]' if complete else '      '} {message}")
        if complete and verification_result:
            verification_result_holder["result"] = verification_result

    verifier.verify_documentation(
        file_path=args.file_path,
        valid_templates=valid_templates,
        local_validation_packages=local_packages,
        get_verification_results_callback=verification_callback
    )

    verification_results = verification_result_holder.get("result")

    if not verification_results:
        print("\n[ABORT] Verification failed. Cannot proceed to validation.")
        sys.exit(1)

    if verification_results.get("ValidateStatus") != True:
        print("\n[ABORT] File is not ready for validation (update required or error).")
        sys.exit(1)

    plan_type = verification_results["PlanType"]
    package_version = args.package_version if args.package_version else verification_results["VersionTemplate"]
    print(f"\n[INFO] PlanType={plan_type}  PackageVersion={package_version}")

    # === Step 2: Load rule callbacks via services ===
    def zip_struct_rules_get():
        return metadataService.get_rules_zip_structure(
            production=production, plan_type=plan_type, validation_package_version=package_version)

    def gpkg_struct_rules_get():
        return metadataService.get_rules_gpkg_structure(
            production=production, plan_type=plan_type, validation_package_version=package_version)

    def gpkg_data_rules_get():
        return metadataService.get_rules_gpkg_data(
            production=production, plan_type=plan_type, validation_package_version=package_version)

    def uat_limit_get(siruta):
        return metadataService.get_uat_limit(
            production=production, plan_type=plan_type, validation_package_version=package_version, siruta=siruta)

    template_url = metadataService.get_document_template(
        production=production, plan_type=plan_type, validation_package_version=package_version)

    # === Step 3: Validation ===
    print("\n--- Validation ---")
    steps_holder = {"total": 0, "done": 0}

    def progressbar_steps(steps):
        steps_holder["total"] = steps

    def progressbar_update():
        steps_holder["done"] += 1
        total = steps_holder["total"]
        done = steps_holder["done"]
        bar = "#" * done + "-" * (total - done)
        print(f"\r  [{bar}] {done}/{total}", end=" ", flush=True)

    def progressbar_end(validation_status):
        print()

    def validation_callback(complete, status_validation=None, message=None, raport=None):
        print(f"  {'[DONE]' if complete else '      '} {message}")
        if raport is not None:
            file_name = Path(args.file_path).stem
            timestamp = datetime.now().strftime("%H_%M_%S_%d_%m_%Y")
            status_label = "Pass" if status_validation else "Fail"
            report_path = output_folder / f"{file_name}_{timestamp}_{status_label}.csv"
            raport.to_csv(report_path, index=False)
            print(f"\n[REPORT] Saved to: {report_path}")

    validator = DocumentValidation()
    validator.validate_documentation(
        file_path=args.file_path,
        verification_results=verification_results,
        production=production,
        validation_package_version=package_version,
        get_validation_results_callback=validation_callback,
        template_url=template_url,
        zip_struct_rules_get=zip_struct_rules_get,
        gpkg_struct_rules_get=gpkg_struct_rules_get,
        gpkg_data_rules_get=gpkg_data_rules_get,
        uat_limit_get=uat_limit_get,
        progressbar_steps=progressbar_steps,
        progressbar_update=progressbar_update,
        progressbar_end=progressbar_end
    )
