# Utility Functions
import os
import re
import yaml
from datetime import datetime
from tempfile import gettempdir
from traceback import format_exc

# File Name Friendly Timestamp
def get_timestamp() -> str:
    now = datetime.now()
    timestamp = now.strftime("%Y-%m-%d_%H-%M-%S")
    return timestamp

# File Name Friendly UserName
def get_safe_username(name: str) -> str:
    # Remove leading '@' and any other special characters to exclude
    return re.sub(r'[^\w\s]', '', name.lstrip('@'))

# Basic open text file function
def open_file(file_path: str):
    with open(file_path, 'r', encoding='utf-8') as file:
        return file.read()

# Reads the file per line in reverse order
# Source: https://thispointer.com/python-read-a-file-in-reverse-order-line-by-line/
def read_reverse_order(file_path: str):
    with open(file_path, 'r', encoding='utf-8') as file:
        # Get all lines in a file as list to reverse order
        lines = file.readlines()
        lines = [line.strip() for line in lines]
        lines = reversed(lines)
        return lines

# Read a YAML-formatted file, useful for configurations
def read_yaml(file_path: str):
    with open(file_path, 'r', encoding='utf-8') as file:
        data = yaml.safe_load(file)
    return data

# Read a plain text file, useful for system prompts
def read_text(file_path: str) -> str:
    text = open_file(file_path)
    return text.strip()

# Determine if the given text has the exact word
# Example 'Word': 'Word-cross' ✓ vs. 'word1-cross' X
def exact_word_match(word: str, text: str) -> bool:
    return re.search(rf'\b{word}\b', text) is not None

# Generate a Chat Session Log filename
def generate_filename(bot_name: str, user_name: str) -> str:
    timestamp = get_timestamp()
    return f'{bot_name}-{user_name}-{timestamp}.log'

# Appends text to existing file path
def append_text_file_path(file_path: str, text=""):
    if not text:
        pass
    else:
        try:
            with open(file_path, 'a', encoding='utf-8') as f:
                f.write(f"{text}\n")
        except Exception as e:
            print(f"{type(e).__name__} writing to '{file_path}':\n{format_exc()}")

# Generates a new file for a given directory with optional print name and text
def generate_file_path(directory: str, file: str, text="", print_name="") -> str:
    path = os.path.join(directory, file)
    print_name = "path" if not print_name else print_name 
    if not os.path.exists(path) and not os.path.isfile(path):
        try:
            os.makedirs(os.path.dirname(path), exist_ok=True)
            with open(path, 'w', encoding='utf-8') as f:
                if not text:
                    pass
                else:
                    f.write(text)
            print(f"Created {print_name} file: {path}")
        except Exception as e:
            print(f"{type(e).__name__} generating '{path}':\n{format_exc()}")
    return path

# Generates a location of error log file by env variable vs. temporary location
def generate_error_path(file='tellmgrambot_error.log') -> str:
    env_var = 'TELLMGRAMBOT_ERRORLOGS_PATH'
    if not os.environ.get(env_var):
        os.environ[env_var] = gettempdir()
        print(f"{env_var} initialized with: {os.environ[env_var]}")
    return generate_file_path(os.environ[env_var], file, f"empty {env_var}")

# Log error messages to a file including an error type and timestamp
def log_error(error: Exception or str, error_type: str, error_filename=generate_error_path()):
    text = f"{get_timestamp()} {error_type}: {error}"
    print(text) # Also log into console
    append_text_file_path(error_filename, text)
