from ..utils.constants import *
from ..utils.vector3 import vec3, rgb, extract
from functools import reduce as reduce 
from ..ray import Ray, get_raycolor
from .. import lights
import numpy as np
from . import Material
from ..utils.image_functions import load_image

class ThinFilmInterference(Material):
    def __init__(self, thickness, noise = 0.,**kwargs):
        super().__init__(**kwargs)
        self.thickness = thickness

        # precomputed reflectance vs cosθI (vertical axis) and thickness (horizontal axis)
        self.thin_film_interference_reflectance = load_image("sightpy/textures/thin_film_interference_n=1.4.png")
        self.thickness_noise = load_image("sightpy/textures/noise.png")
        self.thickness_noise = (self.thickness_noise[:,:,0])
        self.noise_factor = noise

    def get_color(self, scene, ray, hit):
        
        hit.point = (ray.origin + ray.dir * hit.distance) # intersection point
        N = hit.material.get_Normal(hit)     # normal 

        # Ambient
        color = rgb(0.,0.,0.)

        V = ray.dir*-1.                            # direction to ray origin
        

        if ray.depth < hit.surface.max_ray_depth:

            """
            if hit_orientation== UPWARDS:
               #ray enter in the material
            if hit_orientation== UPDOWN:
               #ray get out of the material   
            """

            cosθi = V.dot(N)

            u,v = hit.get_uv()
            thickness = self.thickness 
            if self.noise_factor != 0.:
                thickness += self.noise_factor*(self.thickness_noise[-((v * self.thickness_noise.shape[0]*0.5 ).astype(int)% self.thickness_noise.shape[0]) , (u   * self.thickness_noise.shape[1]*0.5).astype(int) % self.thickness_noise.shape[1]  ].T - 0.5)
                Fim = self.thin_film_interference_reflectance[(cosθi* self.thin_film_interference_reflectance.shape[0]).astype(int),    thickness.astype(int)     ]
            else:
                Fim = self.thin_film_interference_reflectance[(cosθi* self.thin_film_interference_reflectance.shape[0]).astype(int),    int(thickness)    ]
            
            F = vec3(Fim[:,0],Fim[:,1],Fim[:,2])
            # compute reflection
            reflected_ray_dir = (ray.dir - N * 2. * ray.dir.dot(N)).normalize()

            nudged = hit.point + N * .000001                  # M nudged to avoid itself
            color += (scene.ambient_color + get_raycolor(Ray(nudged, reflected_ray_dir, ray.depth + 1, ray.n, ray.reflections + 1, ray.transmissions,  ray.diffuse_reflections), scene))*F
            


            # because the film is very thin (nm) we ignore refraction for transmitted ray.

            transmitted_ray_dir = ray.dir 
            nudged = hit.point - N * .000001  #nudged for transmitted ray
            T = 1. - F
            transmitted_color = get_raycolor( Ray(nudged, transmitted_ray_dir, ray.depth + 1, ray.n, ray.reflections, ray.transmissions + 1,  ray.diffuse_reflections), scene  )*T
            color += transmitted_color
        return color