use crate::components::{ViewMode, WeekView, MonthView, CalendarHeader};
use crate::models::ical::VEvent;
use crate::services::calendar_service::{UserInfo, ExternalCalendar};
use chrono::NaiveDate;
use std::collections::HashMap;
use wasm_bindgen::{closure::Closure, JsCast};
use web_sys::MouseEvent;
use yew::prelude::*;

#[derive(Properties, PartialEq)]
pub struct PrintPreviewModalProps {
    pub on_close: Callback<()>,
    pub view_mode: ViewMode,
    pub current_date: NaiveDate,
    pub selected_date: NaiveDate,
    pub events: HashMap<NaiveDate, Vec<VEvent>>,
    pub user_info: Option<UserInfo>,
    pub external_calendars: Vec<ExternalCalendar>,
    pub time_increment: u32,
    pub today: NaiveDate,
}

#[function_component]
pub fn PrintPreviewModal(props: &PrintPreviewModalProps) -> Html {
    let start_hour = use_state(|| 6u32);
    let end_hour = use_state(|| 22u32);
    let zoom_level = use_state(|| 0.4f64); // Default 40% zoom

    let close_modal = {
        let on_close = props.on_close.clone();
        Callback::from(move |_| {
            on_close.emit(());
        })
    };

    let backdrop_click = {
        let on_close = props.on_close.clone();
        Callback::from(move |e: MouseEvent| {
            if e.target() == e.current_target() {
                on_close.emit(());
            }
        })
    };

    let on_start_hour_change = {
        let start_hour = start_hour.clone();
        let end_hour = end_hour.clone();
        Callback::from(move |e: Event| {
            let target = e.target_dyn_into::<web_sys::HtmlSelectElement>();
            if let Some(select) = target {
                if let Ok(hour) = select.value().parse::<u32>() {
                    if hour < *end_hour {
                        start_hour.set(hour);
                    }
                }
            }
        })
    };

    let on_end_hour_change = {
        let start_hour = start_hour.clone();
        let end_hour = end_hour.clone();
        Callback::from(move |e: Event| {
            let target = e.target_dyn_into::<web_sys::HtmlSelectElement>();
            if let Some(select) = target {
                if let Ok(hour) = select.value().parse::<u32>() {
                    if hour > *start_hour && hour <= 24 {
                        end_hour.set(hour);
                    }
                }
            }
        })
    };


    let format_hour = |hour: u32| -> String {
        if hour == 0 {
            "12 AM".to_string()
        } else if hour < 12 {
            format!("{} AM", hour)
        } else if hour == 12 {
            "12 PM".to_string()
        } else {
            format!("{} PM", hour - 12)
        }
    };

    // Calculate dynamic base unit for print preview
    let calculate_print_dimensions = |start_hour: u32, end_hour: u32, time_increment: u32| -> (f64, f64, f64) {
        let visible_hours = (end_hour - start_hour) as f64;
        let slots_per_hour = if time_increment == 15 { 4.0 } else { 2.0 };
        let calendar_header_height = 80.0; // Calendar header height in print preview
        let week_header_height = 50.0; // Fixed week header height in print preview  
        let header_border = 2.0;   // Week header bottom border (2px solid)
        let container_spacing = 8.0; // Additional container spacing/margins
        let total_overhead = calendar_header_height + week_header_height + header_border + container_spacing;
        let available_height = 720.0 - total_overhead; // Available for time content
        let base_unit = available_height / (visible_hours * slots_per_hour);
        let pixels_per_hour = base_unit * slots_per_hour;
        
        (base_unit, pixels_per_hour, available_height)
    };

    // Calculate print dimensions for the current hour range
    let (base_unit, pixels_per_hour, _available_height) = calculate_print_dimensions(*start_hour, *end_hour, props.time_increment);

    // Effect to update print copy whenever modal renders or content changes
    {
        let start_hour = *start_hour;
        let end_hour = *end_hour;
        let time_increment = props.time_increment;
        let original_base_unit = base_unit;
        use_effect(move || {
            if let Some(window) = web_sys::window() {
                if let Some(document) = window.document() {
                    // Set CSS variables on document root
                    if let Some(document_element) = document.document_element() {
                        if let Some(html_element) = document_element.dyn_ref::<web_sys::HtmlElement>() {
                            let style = html_element.style();
                            let _ = style.set_property("--print-start-hour", &start_hour.to_string());
                            let _ = style.set_property("--print-end-hour", &end_hour.to_string());
                        }
                    }

                    // Copy content from print-preview-content to the hidden print-preview-copy div
                    let copy_content = move || {
                        if let Some(preview_content) = document.query_selector(".print-preview-content").ok().flatten() {
                            if let Some(print_copy) = document.get_element_by_id("print-preview-copy") {
                                // Clone the preview content
                                if let Some(content_clone) = preview_content.clone_node_with_deep(true).ok() {
                                    // Clear the print copy div and add the cloned content
                                    print_copy.set_inner_html("");
                                    let _ = print_copy.append_child(&content_clone);
                                    
                                    // Get the actual rendered height of the print copy div and recalculate base-unit
                                    if let Some(print_copy_html) = print_copy.dyn_ref::<web_sys::HtmlElement>() {
                                        // Temporarily make visible to measure height, then hide again
                                        let original_display = print_copy_html.style().get_property_value("display").unwrap_or_default();
                                        let _ = print_copy_html.style().set_property("display", "block");
                                        let _ = print_copy_html.style().set_property("visibility", "hidden");
                                        let _ = print_copy_html.style().set_property("position", "absolute");
                                        let _ = print_copy_html.style().set_property("top", "-9999px");
                                        
                                        // Now measure the height
                                        let actual_height = print_copy_html.client_height() as f64;
                                        
                                        // Restore original display
                                        let _ = print_copy_html.style().set_property("display", &original_display);
                                        let _ = print_copy_html.style().remove_property("visibility");
                                        let _ = print_copy_html.style().remove_property("position");
                                        let _ = print_copy_html.style().remove_property("top");
                                        
                                        // Recalculate base-unit and pixels-per-hour based on actual height
                                        let visible_hours = (end_hour - start_hour) as f64;
                                        let slots_per_hour = if time_increment == 15 { 4.0 } else { 2.0 };
                                        let calendar_header_height = 80.0; // Calendar header height
                                        let week_header_height = 50.0; // Week header height
                                        let header_border = 2.0;
                                        let container_spacing = 8.0;
                                        let total_overhead = calendar_header_height + week_header_height + header_border + container_spacing;
                                        let available_height = actual_height - total_overhead;
                                        let actual_base_unit = available_height / (visible_hours * slots_per_hour);
                                        let actual_pixels_per_hour = actual_base_unit * slots_per_hour;
                                        
                                        
                                        // Set CSS variables with recalculated values
                                        let style = print_copy_html.style();
                                        let _ = style.set_property("--print-base-unit", &format!("{:.2}", actual_base_unit));
                                        let _ = style.set_property("--print-pixels-per-hour", &format!("{:.2}", actual_pixels_per_hour));
                                        let _ = style.set_property("--print-start-hour", &start_hour.to_string());
                                        let _ = style.set_property("--print-end-hour", &end_hour.to_string());
                                        
                                        // Copy data attributes
                                        let _ = print_copy.set_attribute("data-start-hour", &start_hour.to_string());
                                        let _ = print_copy.set_attribute("data-end-hour", &end_hour.to_string());
                                        
                                        // Recalculate event positions using the new base-unit
                                        let events = print_copy.query_selector_all(".week-event").unwrap();
                                        let scale_factor = actual_base_unit / original_base_unit;
                                        
                                        for i in 0..events.length() {
                                            if let Some(event_element) = events.get(i) {
                                                if let Some(event_html) = event_element.dyn_ref::<web_sys::HtmlElement>() {
                                                    let event_style = event_html.style();
                                                    
                                                    // Get current positioning values and recalculate
                                                    if let Ok(current_top) = event_style.get_property_value("top") {
                                                        if current_top.ends_with("px") {
                                                            if let Ok(top_px) = current_top[..current_top.len()-2].parse::<f64>() {
                                                                let new_top = top_px * scale_factor;
                                                                let _ = event_style.set_property("top", &format!("{:.2}px", new_top));
                                                            }
                                                        }
                                                    }
                                                    
                                                    if let Ok(current_height) = event_style.get_property_value("height") {
                                                        if current_height.ends_with("px") {
                                                            if let Ok(height_px) = current_height[..current_height.len()-2].parse::<f64>() {
                                                                let new_height = height_px * scale_factor;
                                                                let _ = event_style.set_property("height", &format!("{:.2}px", new_height));
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        
                                        web_sys::console::log_1(&format!("Height: {:.2}, Original base-unit: {:.2}, New base-unit: {:.2}, Scale factor: {:.2}", 
                                            actual_height, original_base_unit, actual_base_unit, scale_factor).into());
                                    }
                                }
                            }
                        }
                    };

                    // Copy content immediately
                    copy_content();

                    // Also set up a small delay to catch any async rendering
                    let copy_callback = Closure::wrap(Box::new(copy_content) as Box<dyn FnMut()>);
                    let _ = window.set_timeout_with_callback_and_timeout_and_arguments_0(
                        copy_callback.as_ref().unchecked_ref(),
                        100
                    );
                    copy_callback.forget();
                }
            }
            || ()
        });
    }
    
    let on_print = {
        Callback::from(move |_: MouseEvent| {
            if let Some(window) = web_sys::window() {
                // Print copy is already updated by the use_effect, just trigger print
                let _ = window.print();
            }
        })
    };

    html! {
        <div class="modal-backdrop print-preview-modal-backdrop" onclick={backdrop_click}>
            <div class="modal-content print-preview-modal">
                <div class="modal-header">
                    <h3>{"Print Preview"}</h3>
                    <button class="modal-close" onclick={close_modal.clone()}>{"×"}</button>
                </div>
                <div class="modal-body print-preview-body">
                    <div class="print-preview-controls">
                        {
                            if props.view_mode == ViewMode::Week {
                                html! {
                                    <>
                                        <div class="control-group">
                                            <label for="start-hour">{"Start Hour:"}</label>
                                            <select id="start-hour" onchange={on_start_hour_change}>
                                                {
                                                    (0..24).map(|hour| {
                                                        html! {
                                                            <option value={hour.to_string()} selected={hour == *start_hour}>
                                                                {format_hour(hour)}
                                                            </option>
                                                        }
                                                    }).collect::<Html>()
                                                }
                                            </select>
                                        </div>
                                        <div class="control-group">
                                            <label for="end-hour">{"End Hour:"}</label>
                                            <select id="end-hour" onchange={on_end_hour_change}>
                                                {
                                                    (1..=24).map(|hour| {
                                                        html! {
                                                            <option value={hour.to_string()} selected={hour == *end_hour}>
                                                                {if hour == 24 { "12 AM".to_string() } else { format_hour(hour) }}
                                                            </option>
                                                        }
                                                    }).collect::<Html>()
                                                }
                                            </select>
                                        </div>
                                        <div class="hour-range-info">
                                            {format!("Will print from {} to {}", 
                                                format_hour(*start_hour), 
                                                if *end_hour == 24 { "12 AM".to_string() } else { format_hour(*end_hour) }
                                            )}
                                        </div>
                                    </>
                                }
                            } else {
                                html! {
                                    <div class="month-info">
                                        {"Will print entire month view"}
                                    </div>
                                }
                            }
                        }
                        <div class="zoom-display-info">
                            <label>{"Zoom: "}</label>
                            <span>{format!("{}%", (*zoom_level * 100.0) as i32)}</span>
                            <span class="zoom-hint">{"(scroll to zoom)"}</span>
                        </div>
                        <div class="preview-actions">
                            <button class="btn-primary" onclick={on_print}>{"Print"}</button>
                            <button class="btn-secondary" onclick={close_modal}>{"Cancel"}</button>
                        </div>
                    </div>
                    <div class="print-preview-display" onwheel={{
                        let zoom_level = zoom_level.clone();
                        Callback::from(move |e: WheelEvent| {
                            e.prevent_default(); // Prevent page scroll
                            let delta_y = e.delta_y();
                            let zoom_change = if delta_y < 0.0 { 1.1 } else { 1.0 / 1.1 };
                            let new_zoom = (*zoom_level * zoom_change).clamp(0.2, 1.5);
                            zoom_level.set(new_zoom);
                        })
                    }}>
                        <div class="print-preview-paper" 
                                     data-start-hour={start_hour.to_string()} 
                                     data-end-hour={end_hour.to_string()}
                                     style={format!(
                                         "--print-start-hour: {}; --print-end-hour: {}; --print-base-unit: {:.2}; --print-pixels-per-hour: {:.2}; transform: scale({}); transform-origin: top center;", 
                                         *start_hour, *end_hour, base_unit, pixels_per_hour, *zoom_level
                                     )}>
                            <div class="print-preview-content">
                                <div class={classes!("calendar", match props.view_mode { ViewMode::Week => Some("week-view"), _ => None })}>
                                    <CalendarHeader
                                        current_date={props.current_date}
                                        view_mode={props.view_mode.clone()}
                                        on_prev={Callback::from(|_: MouseEvent| {})}
                                        on_next={Callback::from(|_: MouseEvent| {})}
                                        on_today={Callback::from(|_: MouseEvent| {})}
                                        time_increment={Some(props.time_increment)}
                                        on_time_increment_toggle={None::<Callback<MouseEvent>>}
                                        on_print={None::<Callback<MouseEvent>>}
                                    />
                                    {
                                        match props.view_mode {
                                            ViewMode::Week => html! {
                                                <WeekView
                                                    key={format!("week-preview-{}-{}", *start_hour, *end_hour)}
                                                    current_date={props.current_date}
                                                    today={props.today}
                                                    events={props.events.clone()}
                                                    on_event_click={Callback::noop()}
                                                    user_info={props.user_info.clone()}
                                                    external_calendars={props.external_calendars.clone()}
                                                    time_increment={props.time_increment}
                                                    print_mode={true}
                                                    print_pixels_per_hour={Some(pixels_per_hour)}
                                                    print_start_hour={Some(*start_hour)}
                                                />
                                            },
                                            ViewMode::Month => html! {
                                                <MonthView
                                                    key={format!("month-preview-{}-{}", *start_hour, *end_hour)}
                                                    current_month={props.current_date}
                                                    selected_date={Some(props.selected_date)}
                                                    today={props.today}
                                                    events={props.events.clone()}
                                                    on_day_select={None::<Callback<NaiveDate>>}
                                                    on_event_click={Callback::noop()}
                                                    user_info={props.user_info.clone()}
                                                    external_calendars={props.external_calendars.clone()}
                                                />
                                            },
                                        }
                                    }
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    }
}