import cv2
import numpy as np
import os

# Input
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
ref_path = os.path.join(BASE_DIR, "TestObject_B-ConditionReport.png")  # riferimento manuale
pred_paths = {
	"ORTHO": os.path.join(BASE_DIR, "TestObject_B-AutomaticChangeDetection_ORTHO.png"),
	"TEXTURE": os.path.join(BASE_DIR, "TestObject_B-AutomaticChangeDetection_TEXTURE.png"),
}

out_dir = os.path.join(BASE_DIR, "Results_TestObject_B")
os.makedirs(out_dir, exist_ok=True)

# Carica in grayscale
ref = cv2.imread(ref_path, cv2.IMREAD_GRAYSCALE)
if ref is None:
	raise FileNotFoundError(f"Controlla il file di riferimento: {ref_path}")


def safe_div(a, b):
	return a / b if b != 0 else 0.0


for pred_label, pred_path in pred_paths.items():
	pred = cv2.imread(pred_path, cv2.IMREAD_GRAYSCALE)
	if pred is None:
		raise FileNotFoundError(f"Controlla il file automatico: {pred_path}")

	# Mantieni output con dimensioni identiche al riferimento
	if ref.shape != pred.shape:
		pred = cv2.resize(pred, (ref.shape[1], ref.shape[0]), interpolation=cv2.INTER_NEAREST)

	# Binarizzazione semplice e robusta (1=degrado, 0=sano)
	# Qui il degrado e' rappresentato da pixel piu' scuri.
	min_val = int(min(ref.min(), pred.min()))
	max_val = int(max(ref.max(), pred.max()))
	thr = (min_val + max_val) // 2
	ref_bin = (ref < thr).astype(np.uint8)
	pred_bin = (pred < thr).astype(np.uint8)

	# Maschere confusion matrix
	tp = (ref_bin == 1) & (pred_bin == 1)  # trovate corrette
	fn = (ref_bin == 1) & (pred_bin == 0)  # aree mancate
	fp = (ref_bin == 0) & (pred_bin == 1)  # aree in piu'
	tn = (ref_bin == 0) & (pred_bin == 0)

	# Conteggi
	VP = int(tp.sum())
	FN = int(fn.sum())
	FP = int(fp.sum())
	VN = int(tn.sum())
	TOT = VP + FN + FP + VN

	precision = safe_div(VP, VP + FP)
	recall = safe_div(VP, VP + FN)
	f1 = safe_div(2 * precision * recall, precision + recall)
	accuracy = safe_div(VP + VN, TOT)
	specificity = safe_div(VN, VN + FP)

	print(f"\n=== {pred_label} ===")
	print("Confusion Matrix [ [VP, FN], [FP, VN] ]:")
	print(np.array([[VP, FN], [FP, VN]]))

	print("\nMetriche (classe positiva = DEGRADO):")
	print(f"VP={VP}, FN={FN}, FP={FP}, VN={VN}, Totale={TOT}")

	print(
		"Precisione = VP/(VP+FP): quando il modello dice 'degrado', quante volte ha ragione"
		+ f" -> {precision:.6f} ({precision * 100:.2f}%)"
	)
	print(
		"Recall = VP/(VP+FN): di tutto il degrado reale, quanto viene trovato"
		+ f" -> {recall:.6f} ({recall * 100:.2f}%)"
	)
	print(
		"F1-score = media armonica tra Precisione e Recall"
		+ f" -> {f1:.6f} ({f1 * 100:.2f}%)"
	)
	print(
		"Accuratezza = (VP+VN)/Totale: quota totale di pixel classificati correttamente"
		+ f" -> {accuracy:.6f} ({accuracy * 100:.2f}%)"
	)
	print(
		"Specificita = VN/(VN+FP): sui pixel sani, quanti sono riconosciuti sani"
		+ f" -> {specificity:.6f} ({specificity * 100:.2f}%)"
	)

	report_path = os.path.join(out_dir, f"TestObject_B_metriche_report_{pred_label}.txt")
	with open(report_path, "w", encoding="utf-8") as f:
		f.write("REPORT METRICHE - CONFRONTO PIXEL\n")
		f.write(f"Riferimento: {ref_path}\n")
		f.write(f"Automatico: {pred_path}\n\n")

		f.write("Confusion Matrix [ [VP, FN], [FP, VN] ]\n")
		f.write(f"[[{VP}, {FN}], [{FP}, {VN}]]\n")
		f.write(f"VP={VP}, FN={FN}, FP={FP}, VN={VN}, Totale={TOT}\n\n")

		f.write("Definizioni metriche (classe positiva = DEGRADO)\n")
		f.write("Precisione = VP/(VP+FP): quando il modello dice degrado, quante volte ha ragione.\n")
		f.write(f"Valore: {precision:.6f} ({precision * 100:.2f}%)\n\n")

		f.write("Recall = VP/(VP+FN): di tutto il degrado reale, quanto viene trovato.\n")
		f.write(f"Valore: {recall:.6f} ({recall * 100:.2f}%)\n\n")

		f.write("F1-score = 2*(Precision*Recall)/(Precision+Recall): equilibrio tra precisione e recall.\n")
		f.write(f"Valore: {f1:.6f} ({f1 * 100:.2f}%)\n\n")

		f.write("Accuratezza = (VP+VN)/Totale: quota complessiva di pixel classificati correttamente.\n")
		f.write(f"Valore: {accuracy:.6f} ({accuracy * 100:.2f}%)\n\n")

		f.write("Specificita = VN/(VN+FP): sui pixel sani, quanti sono riconosciuti sani.\n")
		f.write(f"Valore: {specificity:.6f} ({specificity * 100:.2f}%)\n")

	print(f"Report salvato: {report_path}")

	# Mappa colori (BGR):
	# Verde = corrette (TP), Rosso = mancate (FN), Bianco = in piu' (FP), Nero = TN
	out = np.zeros((ref.shape[0], ref.shape[1], 3), dtype=np.uint8)
	out[tp] = (0, 255, 0)       # verde
	out[fn] = (0, 0, 255)       # rosso
	out[fp] = (255, 255, 255)   # bianco

	conf_map_path = os.path.join(out_dir, f"TestObject_B_confusion_map_{pred_label}.png")
	cv2.imwrite(conf_map_path, out)
	print(f"Salvata: {conf_map_path}")
