#!/usr/bin/env python
# -*- coding: utf-8 -*-

## @file main_alpha_blender.py
## @brief This program applies gamma-corrected alpha blending to overlapping projector images.
## @details
## This program finds the overlap between two projected images and computes
## a spatially smooth alpha mask. The mask is gamma-corrected to compensate for
## projector luminance behavior and to avoid visible seams in the blended region.

import cv2
import numpy as np
from config_reader import ConfigReader


class MainAlphaBlender(object):
    """
    @brief This is the main controller class for executing the alpha-blending pipeline.
    @details
    This class loads configuration parameters imported from config_reader, generates a gamma-corrected
    alpha mask, applies it to the selected side of the image, and outputs
    a seamless PNG with adjusted transparency.
    """

    def __init__(self):
        """
        @brief This is the constructor for MainAlphaBlender.
        @details This initializes and loads configuration parameters through ConfigReader.
        @see config_reader.py
        """
        self.__configReader = None
        self.__configReader = ConfigReader()

    def run(self):
        """
        @brief This executes the entire alpha blending process.
        @details
        This function performs the following steps:
          1. Load parameters from configuration.
          2. Load the input image (must be PNG/BGRA).
          3. Estimate the overlap region in pixels.
          4. Generate a linear alpha curve depending on 'left' or 'right' side.
          5. Apply gamma correction (crucial for projector luminance).
          6. Write the alpha-corrected output image.
        @return this will return None.
        @see config_reader.py
        """

        print("--- Starting Alpha Blend Process (Gamma Corrected) ---")

        # 1. Get Configuration
        image_name = self.__configReader.getImageName()
        side = self.__configReader.getSide()
        proj_width_phys = self.__configReader.getProjectedImageWidth()
        dist_phys = self.__configReader.getDistanceBetweenProjectors()
        gamma = self.__configReader.getGamma()

        # 2. Loading Image using OpenCV
        img = cv2.imread(image_name, cv2.IMREAD_UNCHANGED)
        if img is None:
            print(f"Error: Could not load image '{image_name}'")
            return

        # Ensure BGRA format for safe alpha manipulation
        if img.shape[2] == 3:
            img = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)

        height, width = img.shape[:2]

        # 3. Calculate Overlap Ratio and Pixels
        overlap_ratio = 1.0 - (dist_phys / proj_width_phys) if proj_width_phys > 0 else 0.0

        if overlap_ratio <= 0:
            print("Warning: No overlap detected.")
            return

        overlap_pixels = int(width * overlap_ratio)
        print(f"Processing '{side}' | Overlap: {overlap_pixels} pixels | Gamma: {gamma}")

        # 4. Create a linear fade mask for the overlap region
        ## @brief Linear ramp values (0 → 1)
        linear_ramp = np.linspace(0, 1, overlap_pixels)

        # Determine mask direction based on side
        if side == "left":
            ## @brief Left side fades out (1 → 0)
            base_curve = 1.0 - linear_ramp
        elif side == "right":
            ## @brief Right side fades in (0 → 1)
            base_curve = linear_ramp
        else:
            print("Error: Side must be 'left' or 'right'")
            return

        # 5. Apply Gamma Correction
        ## @details Raises the curve to power (1/gamma) to compensate projector response.
        mask_curve = np.power(base_curve, 1.0 / gamma)

        # 6. Apply Alpha Mask to Image
        alpha_channel = img[:, :, 3].astype(float) / 255.0
        mask_block = np.tile(mask_curve, (height, 1))

        if side == "left":
            alpha_channel[:, width - overlap_pixels:] *= mask_block
        else:
            alpha_channel[:, :overlap_pixels] *= mask_block

        img[:, :, 3] = (alpha_channel * 255).astype(np.uint8)

        # Optional RGB burn-in (debug visualization)
        for c in range(3):
            if side == "left":
                roi = img[:, :, c][:, width - overlap_pixels:]
                img[:, :, c][:, width - overlap_pixels:] = (roi * mask_block).astype(np.uint8)
            else:
                roi = img[:, :, c][:, :overlap_pixels]
                img[:, :, c][:, :overlap_pixels] = (roi * mask_block).astype(np.uint8)

        # 7. Save Output
        output_name = f"output_{side}.png"
        cv2.imwrite(output_name, img)
        print(f"Saved: {output_name}")


if __name__ == "__main__":
    """
    @brief Program entry point.
    @details Instantiates MainAlphaBlender and runs the pipeline.
    """
    blender = MainAlphaBlender()
    blender.run()