import glob
import os

import cv2
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as stats
from skimage.metrics import structural_similarity as ssim
from tqdm import tqdm

# use this: https://sketch.io

def calculate_rmse(imageA, imageB):
    err = np.sum((imageA - imageB) ** 2)
    err /= float(imageA.shape[0] * imageA.shape[1])
    return np.sqrt(err)

def compare_images(ground_truth_path, sample_paths):
    results = []
    gt_image = cv2.imread(ground_truth_path, cv2.IMREAD_GRAYSCALE)
    
    if gt_image is None:
        raise ValueError("Ground truth image could not be read. Please check the file path.")
    
    gt_image = gt_image.astype("float") / 255.0
    
    for path in tqdm(sample_paths):
        sample_image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
        
        if sample_image is None:
            print(f"WARNING: Sample image at path {path} could not be read. Skipping this image.")
            continue
        
        sample_image = sample_image.astype("float") / 255.0
        
        rmse_value = calculate_rmse(gt_image, sample_image)
        ssim_value, _ = ssim(gt_image, sample_image, full=True, data_range=1)  # Corrected line
        
        diff_mask = cv2.absdiff(gt_image, sample_image)
        
        # plt.imshow(diff_mask * 255, cmap='gray')
        # plt.title(f'Difference Mask for {os.path.basename(path)}\nRMSE: {rmse_value:.5f} - SSIM: {ssim_value:.5f}')
        # plt.show()
        
        results.append({
            'path': path,
            'rmse': rmse_value,
            'ssim': ssim_value,
            'diff_mask': diff_mask
        })
    
    return results


ground_truth = 'ground_truth.png'
sample_images = glob.glob("samples/*.png")

results = compare_images(ground_truth, sample_images)

for res in results:
    print(f"Image: {res['path']} - RMSE: {res['rmse']} - SSIM: {res['ssim']}")

def calculate_confidence_interval(data, confidence_level=0.95):
    mean = np.mean(data)
    sem = stats.sem(data)
    df = len(data) - 1
    me = sem * stats.t.ppf((1 + confidence_level) / 2, df)
    return mean - me, mean + me

rmse_values = [res['rmse'] for res in results]
ssim_values = [res['ssim'] for res in results]

rmse_mean = np.mean(rmse_values)
rmse_median = np.median(rmse_values)
rmse_stdev = np.std(rmse_values, ddof=1)

ssim_mean = np.mean(ssim_values)
ssim_median = np.median(ssim_values)
ssim_stdev = np.std(ssim_values, ddof=1)

rmse_ci = calculate_confidence_interval(rmse_values)
ssim_ci = calculate_confidence_interval(ssim_values)

print(f"\nRMSE - Mean: {rmse_mean}, Median: {rmse_median}, Std Dev: {rmse_stdev}, 95% CI: {rmse_ci}")
print(f"SSIM - Mean: {ssim_mean}, Median: {ssim_median}, Std Dev: {ssim_stdev}, 95% CI: {ssim_ci}")

print(f"RMSE: {rmse_mean} ± {rmse_ci[1] - rmse_mean}")
print(f"SSIM: {ssim_mean} ± {ssim_ci[1] - ssim_mean}")

def save_average_diff_map(results, save_path='average_diff_map.png'):
    if not results:
        print("No results available to create an average diff map.")
        return
    
    avg_diff_map = None
    
    for res in results:
        if avg_diff_map is None:
            avg_diff_map = np.zeros_like(res['diff_mask'])
        
        avg_diff_map += res['diff_mask']
    
    avg_diff_map /= len(results)
    
    avg_diff_map = (avg_diff_map * 255).astype(np.uint8)
    
    cv2.imwrite(save_path, avg_diff_map)

# Usage
save_average_diff_map(results)
