#!/usr/bin/env python3

import logging
import re
from pathlib import Path
from typing import List, Sequence, Pattern

from ltpylib import files, logs

SKIP_FILE_REGEX: Pattern = re.compile(r"^[^a-zA-Z0-9]*template:skip\s*$")
START_REGEX = re.compile(r"^[^a-zA-Z0-9]*template:start (.*?)$")
END_REGEX = re.compile(r"^[^a-zA-Z0-9]*template:end\s*$")
DEFAULT_CANDIDATE_FILES_GLOBS: Sequence[str] = ('**/*',)
DEFAULT_TEMPLATE_FILES_GLOBS: Sequence[str] = ('**/*.template.*',)


def replace_templates_in_files(
    candidate_files_dir: Path,
    template_dir: Path,
    candidate_files_globs: List[str] = DEFAULT_CANDIDATE_FILES_GLOBS,
    template_files_globs: List[str] = DEFAULT_TEMPLATE_FILES_GLOBS,
    debug_mode: bool = False,
    force_replace: bool = False
) -> bool:
  candidate_files: List[Path] = files.filter_files_with_matching_line(
    files.list_files(candidate_files_dir, candidate_files_globs),
    [SKIP_FILE_REGEX],
    check_n_lines=2
  )
  if not candidate_files:
    logging.warning("No candidate files found: candidate_files_dir=%s candidate_files_globs=%s", candidate_files_dir.as_posix(), candidate_files_globs)
    return False

  logs.log_with_title_sep(logging.DEBUG, 'Candidate Files', '\n'.join([file.absolute().as_posix() for file in candidate_files]))

  template_files: List[Path] = files.list_files(template_dir, template_files_globs)
  if not template_files:
    logging.warning("No template files found: template_dir=%s template_files_globs=%s", template_dir.as_posix(), template_files_globs)
    return False

  logs.log_with_title_sep(logging.DEBUG, 'Template Files', '\n'.join([file.absolute().as_posix() for file in template_files]))

  for template_file in template_files:
    replace_template(candidate_files, template_file, debug_mode=debug_mode, force_replace=force_replace)

  return True


def replace_template(candidate_files: List[Path], template_file: Path, debug_mode: bool = False, force_replace: bool = False):
  template_file_content: str = files.read_file(template_file)

  lines = []
  found_start = False
  search_string: str = ''

  for line in template_file_content.splitlines():
    if found_start:
      if END_REGEX.fullmatch(line):
        break

      lines.append(line)
    elif START_REGEX.fullmatch(line):
      found_start = True
      search_string = START_REGEX.fullmatch(line).group(1)

  if not lines or not search_string:
    logging.error('Something went wrong, skipping template: template_file=%s lines_count=%s search_string=%s', template_file.as_posix(), len(lines), search_string)
    return

  replacement: str = '\n'.join(lines)

  logs.log_with_title_sep(logging.DEBUG, 'template_file', template_file.as_posix())
  logs.log_with_title_sep(logging.DEBUG, 'search_string', search_string)
  logs.log_with_title_sep(logging.DEBUG, 'replacement', replacement)

  if not debug_mode:
    for file in candidate_files:
      if file.absolute().as_posix() == template_file.absolute().as_posix():
        continue

      if files.replace_matches_in_file(file, search_string, replacement, quote_replacement=False, force_replace=force_replace):
        logging.info("Replaced template: %s -> %s", template_file.as_posix(), file.as_posix())


def _main():
  import sys

  result = globals()[sys.argv[1]](*sys.argv[2:])
  if result is not None:
    print(result)


if __name__ == "__main__":
  try:
    _main()
  except KeyboardInterrupt:
    exit(130)
