from __future__ import annotations

import os
import shutil
import sys
from pathlib import Path


SOURCE_PROJECT_DIR = Path(__file__).resolve().parent.parent
if getattr(sys, "frozen", False):
    PROJECT_DIR = Path(sys.executable).resolve().parent
else:
    PROJECT_DIR = SOURCE_PROJECT_DIR
_DEFAULT_WINDOWS_LOCAL_ROOT = Path(r"D:\Hermes\local")
_DEFAULT_POSIX_LOCAL_ROOT = Path.home() / "sunny_erp_local"
LOCAL_ROOT = Path(os.environ.get("SUNNY_ERP_LOCAL_ROOT", str(_DEFAULT_WINDOWS_LOCAL_ROOT if os.name == "nt" else _DEFAULT_POSIX_LOCAL_ROOT)))
LEGACY_LOCAL_SETTINGS_DIR = LOCAL_ROOT / "settings"
LEGACY_PROJECT_DATA_DIR = PROJECT_DIR / "data"
LEGACY_PROJECT_DEBUG_DIR = PROJECT_DIR / "debug"
LEGACY_PROJECT_SHARED_DIR = PROJECT_DIR / "local_server" / "shared"
DATA_DIR = LOCAL_ROOT / "data"
SETTINGS_DIR = PROJECT_DIR / "settings" if os.name == "nt" else LOCAL_ROOT / "settings"
DEBUG_DIR = LOCAL_ROOT / "debug"
LANGUAGE_DIR = PROJECT_DIR / "language"
SHARED_DIR = LOCAL_ROOT / "shared"
MAIL_OUTBOX_DIR = LOCAL_ROOT / "mail_outbox"

DB_PATH = DATA_DIR / "po_internal.sqlite3"
REPORT_CONFIG_PATH = SETTINGS_DIR / "report_template.json"
UI_STATE_PATH = SETTINGS_DIR / "ui_state.json"
COSTING_CACHE_DIR = DATA_DIR / "costing_cache"
SERVER_SETTINGS_PATH = SETTINGS_DIR / "server_settings.json"
AUTH_SETTINGS_PATH = SETTINGS_DIR / "auth_settings.json"
PERMISSIONS_SETTINGS_PATH = SETTINGS_DIR / "permissions_settings.json"

DOWNLOAD_TECH_PACK_SETTINGS_PATH = SETTINGS_DIR / "download_tech_pack_settings.json"
DOWNLOAD_TECH_PACK_DATA_DIR = DATA_DIR / "download_tech_pack"
DOWNLOAD_TECH_PACK_LOG_PATH = DOWNLOAD_TECH_PACK_DATA_DIR / "latest_log.txt"
DOWNLOAD_TECH_PACK_CHECKPOINTS_DIR = DOWNLOAD_TECH_PACK_DATA_DIR / "checkpoints"
DOWNLOAD_TECH_PACK_DOWNLOADS_DIR = DOWNLOAD_TECH_PACK_DATA_DIR / "downloads"

RUN_LOCAL_SERVER_SCRIPT = PROJECT_DIR / "scripts" / "run_local_server.bat"


def _move_file_if_missing(source: Path, target: Path) -> None:
    if not source.exists() or target.exists():
        return
    target.parent.mkdir(parents=True, exist_ok=True)
    try:
        shutil.move(str(source), str(target))
    except OSError:
        return


def _move_dir_if_missing(source: Path, target: Path) -> None:
    if not source.exists() or target.exists():
        return
    target.parent.mkdir(parents=True, exist_ok=True)
    try:
        shutil.move(str(source), str(target))
    except OSError:
        return


def _merge_dir_contents(source: Path, target: Path) -> None:
    if not source.exists():
        return
    target.mkdir(parents=True, exist_ok=True)
    for child in source.iterdir():
        destination = target / child.name
        if destination.exists():
            continue
        try:
            shutil.move(str(child), str(destination))
        except OSError:
            continue


def ensure_runtime_storage() -> None:
    legacy_data_dir = LEGACY_PROJECT_DATA_DIR
    legacy_debug_dir = LEGACY_PROJECT_DEBUG_DIR
    legacy_shared_dir = LEGACY_PROJECT_SHARED_DIR

    DATA_DIR.mkdir(parents=True, exist_ok=True)
    SETTINGS_DIR.mkdir(parents=True, exist_ok=True)
    DEBUG_DIR.mkdir(parents=True, exist_ok=True)
    LANGUAGE_DIR.mkdir(parents=True, exist_ok=True)
    SHARED_DIR.mkdir(parents=True, exist_ok=True)
    MAIL_OUTBOX_DIR.mkdir(parents=True, exist_ok=True)

    _move_file_if_missing(PROJECT_DIR / "report_template.json", REPORT_CONFIG_PATH)
    _move_file_if_missing(PROJECT_DIR / "ui_state.json", UI_STATE_PATH)
    _move_file_if_missing(LEGACY_LOCAL_SETTINGS_DIR / "auth_settings.json", AUTH_SETTINGS_PATH)
    _move_file_if_missing(LEGACY_LOCAL_SETTINGS_DIR / "server_settings.json", SERVER_SETTINGS_PATH)
    _move_file_if_missing(LEGACY_LOCAL_SETTINGS_DIR / "download_tech_pack_settings.json", DOWNLOAD_TECH_PACK_SETTINGS_PATH)
    _move_file_if_missing(LEGACY_LOCAL_SETTINGS_DIR / "report_template.json", REPORT_CONFIG_PATH)
    _move_file_if_missing(LEGACY_LOCAL_SETTINGS_DIR / "ui_state.json", UI_STATE_PATH)

    _move_dir_if_missing(legacy_data_dir / "costing_cache", COSTING_CACHE_DIR)
    _move_dir_if_missing(legacy_data_dir / "download_tech_pack", DOWNLOAD_TECH_PACK_DATA_DIR)

    _move_file_if_missing(legacy_data_dir / "po_internal.sqlite3", DB_PATH)
    _move_file_if_missing(legacy_data_dir / "server_settings.json", SERVER_SETTINGS_PATH)
    _move_file_if_missing(legacy_data_dir / "download_tech_pack_settings.json", DOWNLOAD_TECH_PACK_SETTINGS_PATH)

    if legacy_data_dir.exists():
        _merge_dir_contents(legacy_data_dir, DATA_DIR)

    if legacy_debug_dir.exists():
        _merge_dir_contents(legacy_debug_dir, DEBUG_DIR)

    if legacy_shared_dir.exists():
        for child in legacy_shared_dir.iterdir():
            destination = SHARED_DIR / child.name
            if destination.exists():
                continue
            if child.is_dir():
                shutil.copytree(child, destination)
            else:
                shutil.copy2(child, destination)


ensure_runtime_storage()


def remap_runtime_path(raw_path: str | Path | None) -> str:
    candidate = str(raw_path or "").strip()
    if not candidate:
        return ""

    path = Path(candidate)
    if path.exists():
        return str(path)

    remap_pairs = (
        (LEGACY_PROJECT_DATA_DIR, DATA_DIR),
        (LEGACY_PROJECT_DEBUG_DIR, DEBUG_DIR),
        (LEGACY_PROJECT_SHARED_DIR, SHARED_DIR),
    )

    for legacy_root, new_root in remap_pairs:
        try:
            relative = path.relative_to(legacy_root)
        except Exception:
            continue
        remapped = new_root / relative
        return str(remapped)

    return candidate
