"""Remove file date prefix and replace with creation/modification date."""

from __future__ import annotations

import argparse
import concurrent.futures
import logging
import re
import time
from functools import lru_cache
from pathlib import Path

DETECT_SEPARATORS: str = "-_#.~"
SEP: str = "_"
DATE_PATTERN = re.compile(r"(20|19)\d{2}((0[1-9])|(1[012]))((0[1-9])|([12]\d)|(3[01]))")

logging.basicConfig(level=logging.INFO, format="%(message)s")
logger = logging.getLogger(__name__)


def rename_file(target_path: Path) -> None:
    """Rename file using time marker."""
    filestem = remove_date_prefix(target_path.stem)
    modified, created = target_path.stat().st_mtime, target_path.stat().st_ctime
    time_mark = time.strftime(
        "%Y%m%d",
        time.localtime(max((modified, created))),
    )
    dst_path = target_path.with_name(
        f"{time_mark}{SEP}{filestem}{target_path.suffix}",
    )

    if dst_path == target_path:
        logger.warning(f"{target_path} is the same as {dst_path}, skipping.")
        return

    sequence = 1
    while dst_path.exists() and sequence < 100:
        logger.warning(f"{dst_path} already exists, adding unique suffix.")
        dst_path = dst_path.with_name(
            f"{dst_path.stem}({sequence}){dst_path.suffix}",
        )
        sequence += 1

    try:
        target_path.rename(dst_path)
    except Exception:
        logger.error(f"Rename failed: {target_path} -> {dst_path}")
    else:
        logger.info(f"Rename: {target_path} -> {dst_path}")


@lru_cache(maxsize=1024)
def remove_date_prefix(filestem: str) -> str:
    """Remove date prefix from filename."""
    logger.debug(f"Removing date prefix from: {filestem}")

    match = re.search(DATE_PATTERN, filestem)
    if not match:
        logger.debug(f"No date prefix found: {filestem}")
        return filestem
    b, e = match.start(), match.end()
    if b >= 1 and filestem[b - 1] in DETECT_SEPARATORS:
        filestem = filestem[: b - 1] + filestem[e:]
    elif e < len(filestem) and filestem[e] in DETECT_SEPARATORS:
        filestem = filestem[:b] + filestem[e + 1 :]

    logger.debug(f"Removed date prefix: {filestem}")
    return remove_date_prefix(filestem)


def get_filtered_path(target_paths: list[str]) -> list[Path]:
    """Get filtered path list."""
    logger.debug(f"Getting filtered path list: {target_paths}")

    converted_paths = [Path(t) for t in target_paths]
    valid_paths = [p for p in converted_paths if p.exists()]
    missing_paths = list(set(converted_paths) - set(valid_paths))

    if missing_paths:
        logger.warning(f"Files not found: {missing_paths}, skipped.")

    logger.debug(f"Filtered path list: {valid_paths}")
    return valid_paths


def main() -> None:
    parser = argparse.ArgumentParser(
        prog="filedate", description="Remove file date prefix and replace with creation/modification date."
    )
    parser.add_argument("targets", type=str, nargs="+", help="List of input files")
    parser.add_argument("--debug", "-d", action="store_true", help="Enable debug mode")
    args = parser.parse_args()

    if args.debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    if not args.targets:
        logger.error("Please provide file list.")
        return

    valid_paths = get_filtered_path(args.targets)
    if not valid_paths:
        logger.error("No valid files to process.")
        return

    t0 = time.perf_counter()
    with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
        executor.map(rename_file, valid_paths)
    logger.info(f"Done in {time.perf_counter() - t0:.4f}s")
