import logging
import json
import re
import math
import glob
from deep_translator import GoogleTranslator
from gematria import calculate_gematria  # Ensure this function is correctly defined
import csv

# Configure the logger
# You can uncomment the next line to enable debugging logs
# logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(message)s')
logger = logging.getLogger(__name__)

def process_json_files(start=1, end=52, step=1, rounds="1,-1", length=0, tlang="en", strip_spaces=True,
                      strip_in_braces=True, strip_diacritics=True, translate=False):
    """
    Processes Tripitaka JSON files and performs various text manipulations.

    Parameters:
    - start (int): Start number of the Tripitaka book.
    - end (int): End number of the Tripitaka book.
    - step (int): Step size for character selection.
    - rounds (str): Comma-separated list of round numbers (can include negative values).
    - length (int): Maximum length of the result text.
    - tlang (str): Target language for translation.
    - strip_spaces (bool): Whether to remove spaces from the text.
    - strip_in_braces (bool): Whether to remove text within braces.
    - strip_diacritics (bool): Whether to remove diacritics from the text.
    - translate (bool): Whether to translate the result text.

    Returns:
    - list: A list of dictionaries containing processed data or error messages.
    """
    base_path = "texts/tripitaka"
    translator = GoogleTranslator(source='sa', target=tlang) if translate else None  # Correct source language for Sanskrit
    results = []

    for i in range(start, end + 1):
        file_pattern = f"{base_path}/{i:02}*.json"  # Adjust to Tripitaka file naming
        matched_files = glob.glob(file_pattern)
        if not matched_files:
            logger.warning(f"Mandala {i}: No files found for pattern {file_pattern}.")
            results.append({"error": f"Mandala {i}: No files found for pattern {file_pattern}."})
            continue

        for file_name in matched_files:
            try:
                with open(file_name, 'r', encoding='utf-8') as file:
                    data = json.load(file)
                    full_text = ""
                    for gatha in data.get("gathas", []):  # Safe access to 'gathas'
                        full_text += gatha + " "

                    clean_text = full_text
                    if strip_in_braces:
                        # Remove content within [], {}, <> brackets
                        clean_text = re.sub(r"\[.*?\]|\{.*?\}|\<.*?\>", "", clean_text, flags=re.DOTALL)

                    if strip_diacritics:
                        # Keep only Devanagari characters and spaces
                        clean_text = re.sub(r'[^\u0900-\u097F\s]', '', clean_text)
                        # Remove specific diacritics and punctuation
                        clean_text = re.sub(r'[\u0951-\u0954\u0964\u0965]+', '', clean_text)
                        # Remove Devanagari numerals
                        clean_text = re.sub(r'[०१२३४५६७८९]+', '', clean_text)
                        # Remove additional unwanted characters in one step
                        clean_text = re.sub(r'[:?!\'\-]', '', clean_text)

                    # Normalize spaces
                    clean_text = clean_text.replace("\n\n              ", " ")
                    clean_text = clean_text.replace("\n", " ")
                    clean_text = re.sub(r'\s+', ' ', clean_text).strip()

                    if strip_spaces:
                        clean_text = clean_text.replace(" ", "")

                    text_length = len(clean_text)
                    logger.debug(f"Mandala {i}: Clean text length = {text_length}")

                    if text_length == 0:
                        logger.warning(f"Mandala {i}: No text available after cleaning.")
                        continue  # Skip processing if no text is available

                    # Parse 'rounds', allow floats
                    try:
                        rounds_list = list(map(float, rounds.split(',')))
                    except ValueError as e:
                        logger.error(f"Mandala {i}: Invalid 'rounds' format: {rounds}")
                        results.append({"error": f"Mandala {i}: Invalid 'rounds' format: {rounds}"})
                        continue  # Skip this Mandala due to invalid 'rounds' input

                    result_text = ""

                    for r in rounds_list:
                        abs_r = abs(r)

                        # Determine the number of full passes and the remainder.
                        full_passes = math.floor(abs_r)
                        remainder = abs_r - full_passes

                        # Base number of characters per pass
                        base_chars = text_length // step

                        if base_chars == 0:
                            if abs_r > 1:  # Changed from >=1 to >1
                                # When step > text_length and rounds >1, pick 1 character per full pass
                                chars_per_full_pass = 1
                                logger.debug(f"Mandala {i}: step > text_length ({step} > {text_length}), selecting 1 character per full pass.")
                            else:
                                # No characters to pick
                                chars_per_full_pass = 0
                                logger.debug(f"Mandala {i}: step > text_length ({step} > {text_length}) and rounds <=1, no characters selected.")
                            # For remainder, since base_chars=0, no remainder characters
                            chars_for_remainder = 0
                        else:
                            # Normal case
                            chars_per_full_pass = base_chars
                            chars_for_remainder = math.floor(base_chars * remainder)  # Partial pass
                            logger.debug(f"Mandala {i}: Normal case, chars_per_full_pass = {chars_per_full_pass}, chars_for_remainder = {chars_for_remainder}")

                        if r > 0:
                            current_index = (step - 1) % text_length
                            direction = 1
                        else:
                            current_index = (text_length - step) % text_length
                            direction = -1

                        pass_result = ""

                        # Full passes, keep only the last pass
                        for pass_num in range(1, full_passes + 1):
                            current_pass_chars = ""
                            for _ in range(chars_per_full_pass):
                                if chars_per_full_pass == 0:
                                    break
                                current_pass_chars += clean_text[current_index]
                                current_index = (current_index + direction * step) % text_length

                            # Keep only the last full pass
                            if pass_num == full_passes:
                                pass_result = current_pass_chars
                                logger.debug(f"Mandala {i}: Pass {pass_num}, pass_result = {pass_result}")

                        # Remainder pass for fractional rounds
                        if remainder > 0 and chars_for_remainder > 0:
                            current_pass_chars = ""
                            for _ in range(chars_for_remainder):
                                current_pass_chars += clean_text[current_index]
                                current_index = (current_index + direction * step) % text_length
                            pass_result += current_pass_chars
                            logger.debug(f"Mandala {i}: Remainder pass_result = {pass_result}")

                        # Handle cases where step > text_length and chars_per_full_pass=1
                        if base_chars == 0 and chars_per_full_pass == 1 and full_passes > 0:
                            # pass_result already contains the last character picked
                            pass
                        elif base_chars == 0 and chars_per_full_pass == 0 and full_passes > 0:
                            # When no characters are picked, skip appending
                            pass

                        result_text += pass_result

                    logger.debug(f"Result text for Mandala {i}: {result_text}")

                    if length != 0:
                        result_text = result_text[:length]
                        logger.debug(f"Mandala {i}: Result text truncated to length {length}.")

                    # Translate the result text if required
                    try:
                        translated_text = translator.translate(result_text) if translator and result_text else ""
                    except Exception as e:
                        logger.error(f"Translation error: {e}")
                        translated_text = ""

                    # Calculate the Gematria sum
                    try:
                        result_sum = calculate_gematria(result_text)
                    except Exception as e:
                        logger.error(f"Mandala {i}: Gematria calculation error: {e}")
                        result_sum = None

                    if result_text:
                        result = {
                            'book': f"Tripitaka {i}.",
                            'title': f'{data.get("title", "Unknown Title")} {data.get("book_name", "Unknown Book")} {data.get("chapter", "")}',
                            'result_text': result_text,
                            'result_sum': result_sum,
                            'translated_text': translated_text,
                            'source_language': "sa",
                        }
                        results.append(result)

            except (FileNotFoundError, json.JSONDecodeError, KeyError) as e:
                logger.error(f"Mandala {i}: Error processing {file_name}: {e}")
                results.append({"error": f"Mandala {i}: Error processing {file_name}: {e}"})
            except Exception as e:
                logger.error(f"Mandala {i}: Unexpected error processing {file_name}: {e}")
                results.append({"error": f"Mandala {i}: Unexpected error processing {file_name}: {e}"})

    return results if results else None

# Tests
test_results = [
    (process_json_files(1,1,386,"1,-1", translate=True),"अअमुोच्टेकोसचण")
]

# Function to run tests
def run_tests(test_results):
    all_tests_passed = True
    for idx, (result, expected) in enumerate(test_results):
        if expected is None:  # Check if no result is expected
            if not result:
                logger.warning(f"Test {idx}: Passed (Expected no results, got no results.)")
            else:
                # Extract result_text from the first result
                result_text = result[0].get('result_text', None)
                logger.error(f"Test {idx}: Failed (Expected no results, but got: {result_text})")
                all_tests_passed = False
        else:
            # Check if result is not empty before accessing elements
            if result:
                result_text = result[0].get("result_text")
                if result_text == expected:
                    logger.warning(f"Test {idx}: Passed (Expected: '{expected}', Got: '{result_text}')")
                else:
                    logger.error(f"Test {idx}: Failed (Expected: '{expected}', but got: '{result_text}')")
                    all_tests_passed = False
            else:
                logger.error(f"Test {idx}: Failed (Expected: '{expected}', but got no results)")
                all_tests_passed = False

    if all_tests_passed:
        logger.info("All round tests passed.")
    else:
        logger.info("Some tests failed. Please check the error messages above.")

# Run the tests
run_tests(test_results)