/*
 * File: Screen_EEPROM_Write.c
 *
 * Created: Created: Monday September 2025 16:12:05
 *   Author: Chris
 */


// ============================================================================================
// Includes
#include "../Screens.h"
#include "../Easings.h"
#include "../UI_Control.h"
#include "../EEPROM_M24C64.h"

#include "../Display.h"
#include "../Display_Color.h"
#include "../Display_Objects.h"
#include "../Display_Default_Configurations.h"


// ============================================================================================
// Defines
#define COLOR_DOT_ACTIVE           0xFFFF    // Pure White	#FFFFFF
#define COLOR_DOT_INACTIVE         0x0842    // Dark Gray	#404450

#define DOT_ANIMATION_SPEED        8

// Animation timing configuration
#define TEXT_FADE_START_FRAME      70   // Start fading text earlier for overlap
#define TEXT_FADE_DURATION         30   // Longer fade for smoother transition
#define IMAGE_FADE_START_FRAME     80   // Image starts fading in
#define IMAGE_FADE_DURATION        20   // Longer fade for smoother appearance
#define ANIMATION_END_FRAME        160  // Total animation duration


// ============================================================================================
// Variables
extern const uint8_t _Font_DejaVu_Sans_Mono_Bold_15x26[];

extern const uint16_t _Image_Check_Green_64x64[];
extern const uint16_t _Image_Check_Green_128x128[];
extern const uint16_t _Image_Failed_Red_64x64[];
extern const uint16_t _Image_Failed_Red_128x128[];

static Object_ID    _Object_Text_Writing;
static Object_ID    _Object_Dots[3];
static Object_ID    _Object_Image;

static bool	        _Code_Correct;
static int  	    _Counter;
static uint32_t 	_EEPROM_Write_Status;
static int32_t      _Dot_Animation_Phase;

static Display_Color _Text_Original_Color;
static Display_Color _Dot_Active_Original_Color;
static Display_Color _Dot_Inactive_Original_Color;


// ============================================================================================
// Function Declarations
void Screen_Setup_EEPROM_Write(Screen_Transition_Direction direction_out, Screen_Transition_Direction direction_in, Easing type, uint32_t frame_duration, bool code_correct);

static void Update_Dot_Animation(void);

static void Screen_Init                (Screen_Transition_Direction direction_out, Screen_Transition_Direction direction_in, Easing type, uint32_t frame_duration);
static void Screen_Tick                (void);
static void Screen_Click               (uint button_return_value);
static void Screen_Touch_Event         (int16_t x, int16_t y);
static void Screen_Action_CW           (Object_ID object_id);
static void Screen_Action_CCW          (Object_ID object_id);
static void Screen_On_Object_Focused   (Object_ID object_id);
static void Screen_On_Object_Defocused (Object_ID object_id);
static void Screen_On_Object_Select    (Object_ID object_id);
static void Screen_On_Object_Deselect  (Object_ID object_id);


/*******************************************************************
    Functions
*******************************************************************/
void Screen_Setup_EEPROM_Write(Screen_Transition_Direction direction_out, Screen_Transition_Direction direction_in, Easing type, uint32_t frame_duration, bool code_correct)
{
    _Code_Correct = code_correct;
   
    Screen_Init(direction_out, direction_in, type, frame_duration);

    _Counter                = 0;
    _Dot_Animation_Phase	= 0;

    if(_Code_Correct) {
        EEPROM_Trigger_Update();
    }

	_EEPROM_Write_Status = EEPROM_STATUS_NONE;
}

void Screen_Init(Screen_Transition_Direction direction_out, Screen_Transition_Direction direction_in, Easing type, uint32_t frame_duration)
{
    // _Screen_Last                   = Screen_Init;    // I don't want that here...
    _Screen_Tick                   = Screen_Tick;
    _Screen_Click                  = Screen_Click;
    _Screen_Touch_Event            = Screen_Touch_Event;
    _Screen_Action_CW              = Screen_Action_CW;
    _Screen_Action_CCW             = Screen_Action_CCW;
    _Screen_On_Objects_Focused     = Screen_On_Object_Focused;
    _Screen_On_Objects_Defocused   = Screen_On_Object_Defocused;
    _Screen_On_Object_Select       = Screen_On_Object_Select;
    _Screen_On_Object_Deselect     = Screen_On_Object_Deselect;

    Display_Objects_Clear();
    Display_Screen_Transition_Start(direction_out, direction_in, type, frame_duration);


    //////////////////////////////
    // Add Display Objects here //
    //////////////////////////////
    _Text_Original_Color = DISPLAY_COLOR_LIGHTGREY;
    _Dot_Active_Original_Color = COLOR_DOT_ACTIVE;
    _Dot_Inactive_Original_Color = COLOR_DOT_INACTIVE;

    Font_ID Font_Text = Display_Objects_Add_Font(_Font_DejaVu_Sans_Mono_Bold_15x26, 0);

    if(_Code_Correct) {
        _Object_Text_Writing = Display_Objects_Add_Text(CENTER_BOTTOM, BOTH_IN_PERCENT, 50, 50, NOT_SELECTABLE, "Writing EEPROM", Font_Text, _Text_Original_Color, NO_STYLE, NO_ANIMATION);

        for(int i = 0; i < 3; i++) {
            _Object_Dots[i] = Display_Objects_Add_Circle_Frame(CENTER_MIDDLE, BOTH_IN_PERCENT, 50 + (i-1) * 6, 60, NOT_SELECTABLE, _Dot_Inactive_Original_Color, 4, 1, NO_STYLE, NO_ANIMATION);
    	}
        
        _Object_Image = Display_Objects_Add_Image(CENTER_MIDDLE, BOTH_IN_PERCENT, 50, 50, NOT_SELECTABLE, _Image_Check_Green_128x128, 0, NO_STYLE, NO_ANIMATION);
        Display_Objects_Update_Enabled(_Object_Image, false);
    }
    else {
        Display_Objects_Add_Text(CENTER_MIDDLE, BOTH_IN_PERCENT, 50, 50, NOT_SELECTABLE, "Code Incorrect", Font_Text, _Text_Original_Color, NO_STYLE, NO_ANIMATION);
    }

    _Screen_Idle_Counter_Disable = true;

    Display_Select_Object();
}

void Screen_Tick(void)
{
    if(_Code_Correct) {
        Update_Dot_Animation();
    }
    
    if(_Counter == IMAGE_FADE_START_FRAME && _Code_Correct)
    {
        if(_EEPROM_Write_Status == EEPROM_STATUS_NONE) {
			_EEPROM_Write_Status = EEPROM_Get_Write_Status();
		}

        Display_Objects_Update_Enabled(_Object_Text_Writing, false);
        for(int i = 0; i < 3; i++) {
            Display_Objects_Update_Enabled(_Object_Dots[i], false);
        }

        if(_EEPROM_Write_Status == EEPROM_STATUS_WRITE_OK) {
			Display_Objects_Update_Enabled(_Object_Image, true);
		} else if(_EEPROM_Write_Status == EEPROM_STATUS_WRITE_FAILED) {
            Display_Objects_Update_Image(_Object_Image, _Image_Failed_Red_128x128);
			Display_Objects_Update_Enabled(_Object_Image, true);
		}

        // Display_Objects_Update_Alpha(_Object_Image, 0);
        Display_Objects_Update_Scale(_Object_Image, 0);
    }

    // Smooth text and dots fade-out (overlapping with image fade-in)
    if(_Counter >= TEXT_FADE_START_FRAME && _Counter < (TEXT_FADE_START_FRAME + TEXT_FADE_DURATION) && _Code_Correct)
    {
        float Fade_Progress = (float)(_Counter - TEXT_FADE_START_FRAME) / (float)TEXT_FADE_DURATION;
        
        // Use Ease_Out_Cubic for smooth, natural fade (accelerates at start, decelerates at end)
        float Eased_Progress = Ease_Out_Cubic(Fade_Progress);
        
        // Calculate inverse progress for fade-out (1.0 -> 0.0)
        float Fade_Out = 1.0f - Eased_Progress;
        
        // Fade text to background color
        Display_Color Faded_Text = Display_Color_Interpolate_Float(_Text_Original_Color, DISPLAY_COLOR_BLACK, Eased_Progress);
        Display_Objects_Update_Color(_Object_Text_Writing, Faded_Text);
        
        // Fade dots to background
        Display_Color Faded_Dot_Active = Display_Color_Interpolate_Float(_Dot_Active_Original_Color, DISPLAY_COLOR_BLACK, Eased_Progress);
        Display_Color Faded_Dot_Inactive = Display_Color_Interpolate_Float(_Dot_Inactive_Original_Color, DISPLAY_COLOR_BLACK, Eased_Progress);
        
        // Apply faded colors while maintaining animation state
        int Active_Dot = _Dot_Animation_Phase / DOT_ANIMATION_SPEED;
        for(int i = 0; i < 3; i++) {
            Display_Color Dot_Color = (i == Active_Dot) ? Faded_Dot_Active : Faded_Dot_Inactive;
            Display_Objects_Update_Color(_Object_Dots[i], Dot_Color);
        }
    }
    
    // Disable text and dots after fade-out completes
    if(_Counter == (TEXT_FADE_START_FRAME + TEXT_FADE_DURATION) && _Code_Correct)
    {
        Display_Objects_Update_Enabled(_Object_Text_Writing, false);
        for(int i = 0; i < 3; i++) {
            Display_Objects_Update_Enabled(_Object_Dots[i], false);
        }
    }

    // Smooth image fade-in with extended duration and better easing
    if(_Counter >= IMAGE_FADE_START_FRAME && _Counter < (IMAGE_FADE_START_FRAME + IMAGE_FADE_DURATION) && _Code_Correct)
    {
        float Fade_Progress = (float)(_Counter - IMAGE_FADE_START_FRAME) / (float)IMAGE_FADE_DURATION;
        
        // Use Ease_Out_Cubic for smooth, elegant appearance
        // This creates a fast start that gradually slows down - feels very natural
        float Eased_Progress = Ease_Out_Cubic(Fade_Progress);
        
        // Convert to alpha value (0-255)
        uint8_t Alpha_Value = (uint8_t)(Eased_Progress * 255.0f);
        
        Display_Objects_Update_Scale(_Object_Image, Eased_Progress);

        // Apply alpha to the appropriate image
        // Display_Objects_Update_Alpha(_Object_Image, Alpha_Value);
    }

    // Transition to next screen after animation completes
    if(_Counter >= ANIMATION_END_FRAME) {
		_Screen_Idle_Counter_Disable = false;
		Screen_Setup_Settings(TRANSITION_DOWN, TRANSITION_DOWN, SCREEN_TRANSITION_DEFAULT_EASING, SCREEN_TRANSITION_DEFAULT_FRAMES, 4);
	}

    _Counter++;
}

void Screen_Click(uint button_return_value)
{

}

void Screen_Touch_Event(int16_t x, int16_t y)
{

}

void Screen_Action_CW(Object_ID object_id)
{

}

void Screen_Action_CCW(Object_ID object_id)
{

}

void Screen_On_Object_Focused(Object_ID object_id)
{

}

void Screen_On_Object_Defocused(Object_ID object_id)
{

}

void Screen_On_Object_Select(Object_ID object_id)
{

}

void Screen_On_Object_Deselect(Object_ID object_id)
{
    if(_Counter >= 120) {
        _Screen_Idle_Counter_Disable = false;
		Screen_Setup_Settings(TRANSITION_DOWN, TRANSITION_DOWN, SCREEN_TRANSITION_DEFAULT_EASING, SCREEN_TRANSITION_DEFAULT_FRAMES, 4);
	}
}


/*******************************************************************
    Internal Functions
*******************************************************************/
void Update_Dot_Animation(void)
{
    _Dot_Animation_Phase++;

    if(_Dot_Animation_Phase >= (DOT_ANIMATION_SPEED * 3)) {
        _Dot_Animation_Phase = 0;
    }
    
    // Determine which dot should be active
    int Active_Dot = _Dot_Animation_Phase / DOT_ANIMATION_SPEED;
    
    // Update dot colors
    for(int i = 0; i < 3; i++) {
        Display_Color Dot_Color = (i == Active_Dot) ? _Dot_Active_Original_Color : _Dot_Inactive_Original_Color;
        Display_Objects_Update_Color(_Object_Dots[i], Dot_Color);
    }
}