import pytesseract
from PIL import Image, ImageEnhance, ImageFilter
# import fitz
# import pypdf
import os
import cv2
import numpy as np
import spacy
import re
from spacy.tokens import Doc
import json


def download_model(model_name):
    spacy.cli.download(model_name)

os.environ['TESSDATA_PREFIX'] = '/opt/homebrew/share/tessdata'
pytesseract.pytesseract.tesseract_cmd = '/opt/homebrew/bin/tesseract'
tessdata_dir_config = '--tessdata-dir "/opt/homebrew/share/tessdata"'


# load a spaCy model
try:
    nlp = spacy.load("de_core_news_lg")
except OSError:
    print("Model not found. Downloading...")
    download_model("de_core_news_lg")
    nlp = spacy.load("de_core_news_lg")


def run_script():
    return "Processing completed"

def replace_unwanted_characters(word):
    # Erlaube nur Zeichen a-z, A-Z, ä, ü, ö, Ä, Ü, Ö, ß, 1-9, . , ' / & % ! " < > + * # ( ) € und -
    allowed_chars = r"[^a-zA-ZäüöÄÜÖß0-9.,'`/&%!\"<>+*#()\€_:-]"
    return re.sub(allowed_chars, '', word)


def clean_newlines(text):
    # Replace two or more consecutive "\n" characters with a single "\n"
    cleaned_text = re.sub(r'\n{2,}', '\n', text)

    # Replace remaining "\n" characters with a space
    cleaned_text = cleaned_text.replace("\n", " ")

    return cleaned_text

def process_image(image, use_mock=False):
    #print("Image size:", image.size)
    #print("Image format:", image.format)
    
    if image is None or image.size == 0:
        raise ValueError("Invalid or empty image passed to process_image")

    if use_mock:
        # Return a simple mock image     
        image = Image.new('RGB', (100, 100), color='red')
        return image
    
    # Convert image to OpenCV format
    image = np.array(image)

    # Convert image to grayscale
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    # Binarization
    #_,  image = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

    # Scale image
    desired_width = 5000
    aspect_ratio = image.shape[1] / image.shape[0] # width / height
    desired_height = int(desired_width / aspect_ratio)

    image = cv2.resize(image, (desired_width, desired_height), interpolation=cv2.INTER_AREA)    
    
    # Increase contrast using histogram equalization
    #image = cv2.equalizeHist(image)

    # Noise reduction with a Median filter
    #image = cv2.medianBlur(image, 1)

    # Skew correction
    coords = np.column_stack(np.where(image > 0))
    angle = cv2.minAreaRect(coords)[-1]
    if angle < -45:
        angle = -(90 + angle)
    else:
        angle = -angle
    (h, w) = image.shape[:2]
    center = (w // 2, h // 2)
    M = cv2.getRotationMatrix2D(center, angle, 1.0)
    image = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

    # Convert back to PIL.Image format
    image = Image.fromarray(image)
      # Increase contrast
    #enhancer = ImageEnhance.Contrast(image)
    #image = enhancer.enhance(0.9)
    sharpness = ImageEnhance.Sharpness(image)
    image = sharpness.enhance(0.2) 
    
    # Apply blurring filter
    #image = image.filter(ImageFilter.GaussianBlur(radius=0.03))
    
    return image

def convert_pdf_to_images(pdf_data):
    images = []

    with open(pdf_data, 'rb') as file:
        reader = pypdf.PdfReader(file)
        num_pages = len(reader.pages)

        for i in range(num_pages):
            page = reader.pages[i]
            img = page.to_image(resolution=300)
            images.append(img)

    return images

def scale_coordinates(coords, image_size):
    # Convert the fractional coordinates into actual pixel values
    left = coords['left'] * image_size[0]
    top = coords['top'] * image_size[1]
    right = coords['right'] * image_size[0]
    bottom = coords['bottom'] * image_size[1]
    #print("scaled coordinates:", left, top, right, bottom)
    
    return (left, top, right, bottom)

def crop_image(image, coordinates):
    coordinates = scale_coordinates(coordinates, image.size)
    return image.crop(coordinates)

def extract_coordinates(htmlwithcoords):
    from bs4 import BeautifulSoup

    soup = BeautifulSoup(htmlwithcoords, 'html.parser')
    coordinates = []
    for word in soup.find_all(class_='ocrx_word'):
        bbox = word['title'].split(';')[0].split(' ')[1:]
        left, top, right, bottom = map(int, bbox)
        coordinates.append({'left': left, 'top': top, 'right': right, 'bottom': bottom})
    return coordinates

def process_text(extracted_text):
    extracted_text = clean_newlines(extracted_text)
    return extracted_text

    

def process_files(file_path):
    results = []

    print("Processing file:", file_path)


    with open(file_path, 'rb') as file:
        filename = file_path
        file_extension = filename.split('.')[-1].lower()

        mime_types = {
            'jpg': 'image/jpeg',
            'jpeg': 'image/jpeg',
            'png': 'image/png',
            'gif': 'image/gif',
            'bmp': 'image/bmp',
            'tiff': 'image/tiff',
            'pdf': 'application/pdf',
        }

        file_type = mime_types.get(file_extension, 'application/octet-stream').split('/')[-1]
        if file_type not in ['jpg', 'jpeg', 'png', 'pdf', 'tiff']:
            raise ValueError('Invalid file type.')

        if file_type == 'pdf':
            pdf_data = file.read()
            images = convert_pdf_to_images(pdf_data)
            extracted_text = ''

            for img in images:
                img = process_image(img)
                if img is None or img.size == (0, 0):
                    raise ValueError("Failed to convert PDF page to image")
                text = pytesseract.image_to_string(img, lang='deu')
                extracted_text += text
            extracted_text = process_text(extracted_text)
        else:
            image = Image.open(file_path)
            image = process_image(image)

            try:
                extracted_text = pytesseract.image_to_string(image)
            except pytesseract.pytesseract.TesseractError as e:
                print(f"An error occurred during OCR processing: {e}")
                extracted_text = ""  

            extracted_text = process_text(extracted_text)

        result = {
            'filename': filename,
            'file_type': file_type,
            'extracted_text': extracted_text,
        }
        results.append(result)
        print("text detected:", result)

    return results


# Example usage:
#files = ['image1.jpg', 'document1.pdf']  # Replace with actual paths to your files
#coordinates_list = [[100, 100, 400, 400], [50, 50, 200, 200]]  # Example coordinates

# Process the files
##processed_results = process_files(files, coordinates_list)

# Output the results
#for result in processed_results:
#    print(json.dumps(result, ensure_ascii=False, indent=2))
