from PIL import Image, ImageFilter, ImageOps, ImageFile
import numpy as np
from typing import Literal
from .common_crop import threshold_from_power, group_close_values

ImageFile.LOAD_TRUNCATED_IMAGES = True


'''
Crops inter-panel empty spaces (ignores empty spaces near borders - for that use crop margins).

    Parameters:
            img (PIL image): A PIL image.
            direction (horizontal or vertical or both): To crop rows (horizontal), cols (vertical) or both.
            keep (float): Distance to keep between panels after cropping (in percentage relative to the original distance).
            background_color (string): 'white' for white background, anything else for black.
    Returns:
            img (PIL image): A PIL image after cropping empty sections.
'''
def crop_empty_inter_panel(img, direction: Literal["horizontal", "vertical", "both"], keep=0.04, background_color='white'):
    img_temp = img
    
    if img.mode != 'L':
        img_temp = ImageOps.grayscale(img_temp)
        
    if background_color != 'white':
        img_temp = ImageOps.invert(img_temp)
        
    img_mat = np.array(img)
    
    power = 1
    img_temp = ImageOps.autocontrast(img_temp, 1).filter(ImageFilter.BoxBlur(1))
    img_temp = img_temp.point(lambda p: 255 if p <= threshold_from_power(power) else 0)
    
    if direction in ["horizontal", "both"]:
        rows_idx_to_remove = empty_sections(img_temp, keep, horizontal=True)
        img_mat = np.delete(img_mat, rows_idx_to_remove, 0)
        
    if direction in ["vertical", "both"]:
        cols_idx_to_remove = empty_sections(img_temp, keep, horizontal=False)
        img_mat = np.delete(img_mat, cols_idx_to_remove, 1)

    return Image.fromarray(img_mat)


'''
Finds empty sections (excluding near borders).

    Parameters:
            img (PIL image): A PIL image.
            keep (float): Distance to keep between panels after cropping (in percentage relative to the original distance).
            horizontal (boolean): True to find empty rows, False to find empty columns.
    Returns:
            Itertable (list or NumPy array): indices of rows or columns to remove.
'''
def empty_sections(img, keep, horizontal=True):
    axis = 1 if horizontal else 0
    
    img_mat = np.array(img)
    img_mat_max = np.max(img_mat, axis=axis)
    img_mat_empty_idx = np.where(img_mat_max == 0)[0]
        
    empty_sections = group_close_values(img_mat_empty_idx, 1)
    sections_to_remove = []
    for section in empty_sections:
        if section[1] < img.size[1] * 0.99 and section[0] > img.size[1] * 0.01: # if not near borders
            sections_to_remove.append(section)
        
    if len(sections_to_remove) != 0:
        sections_to_remove_after_keep = [(int(x1+(keep/2)*(x2-x1)), int(x2-(keep/2)*(x2-x1))) for x1,x2 in sections_to_remove]
        idx_to_remove = np.concatenate([np.arange(x1, x2) for x1,x2 in sections_to_remove_after_keep])

        return idx_to_remove
    
    return []



