use ely_browser_core::BrowserSnapshot;
use ely_domain::{BrowserTab, ProfileKind, TabId};
use gpui::{AnyElement, Bounds, Context, Pixels, Point};

use crate::services::ProfileDataMode;

use super::{
    ElyShell,
    web_surface_permissions::web_surface_site_permissions_for_tab,
    web_surface_state::WebSurfaceState,
    web_surface_view::{
        render_failed_web_surface, render_loading_web_surface, render_ready_web_surface,
    },
};

impl ElyShell {
    pub(super) fn render_external_web_canvas(
        &mut self,
        tab: &BrowserTab,
        snapshot: &BrowserSnapshot,
        cx: &mut Context<Self>,
    ) -> AnyElement {
        let state_entity = cx.entity().clone();
        let Some(profile_data_mode) = profile_data_mode_for(tab, snapshot) else {
            return render_failed_web_surface(tab, "Profile context is unavailable.", state_entity);
        };

        let permissions = web_surface_site_permissions_for_tab(tab, snapshot);
        self.web_surfaces.ensure_surface(tab, profile_data_mode, &permissions);

        match self.web_surfaces.state(tab.id()) {
            Some(WebSurfaceState::Ready(frame)) => {
                render_ready_web_surface(frame, tab, state_entity)
            }
            Some(WebSurfaceState::Failed { message, .. }) => {
                render_failed_web_surface(tab, message.as_str(), state_entity)
            }
            Some(WebSurfaceState::Loading { previous_frame: Some(frame), .. }) => {
                render_ready_web_surface(frame, tab, state_entity)
            }
            Some(WebSurfaceState::Loading { previous_frame: None, .. }) | None => {
                render_loading_web_surface(tab, state_entity)
            }
        }
    }

    pub(super) fn tick_external_web_surfaces(&mut self) -> bool {
        self.web_surfaces.tick()
    }

    pub(super) fn record_external_web_viewport(
        &mut self,
        tab_id: TabId,
        bounds: Bounds<Pixels>,
        cx: &mut Context<Self>,
    ) {
        if self.web_surfaces.record_viewport_size(&tab_id, bounds) {
            cx.notify();
        }
    }

    pub(super) fn scroll_external_web_viewport(
        &mut self,
        tab_id: TabId,
        requested_url: String,
        delta: Point<Pixels>,
        cx: &mut Context<Self>,
    ) {
        if self.web_surfaces.record_scroll_delta(&tab_id, requested_url.as_str(), delta) {
            cx.notify();
        }
    }

    pub(super) fn hover_external_web_viewport(
        &mut self,
        tab_id: TabId,
        position: Point<Pixels>,
        cx: &mut Context<Self>,
    ) {
        if self.web_surfaces.record_hover_point(&tab_id, position) {
            cx.notify();
        }
    }

    pub(super) fn click_external_web_viewport(
        &mut self,
        tab_id: TabId,
        requested_url: String,
        position: Point<Pixels>,
        window: &mut gpui::Window,
        cx: &mut Context<Self>,
    ) {
        self.focus_handle.focus(window);
        if self.web_surfaces.record_click_point(&tab_id, requested_url.as_str(), position) {
            cx.notify();
        }
    }

    pub(super) fn type_text_in_external_web_viewport(
        &mut self,
        tab_id: TabId,
        requested_url: String,
        text: &str,
        cx: &mut Context<Self>,
    ) -> bool {
        if self.web_surfaces.record_typed_text(&tab_id, requested_url.as_str(), text) {
            cx.notify();
            return true;
        }

        false
    }
}

fn profile_data_mode_for(tab: &BrowserTab, snapshot: &BrowserSnapshot) -> Option<ProfileDataMode> {
    snapshot.profiles.iter().find(|profile| profile.id() == tab.profile_id()).map(|profile| {
        match profile.kind() {
            ProfileKind::Standard => ProfileDataMode::Persistent,
            ProfileKind::Private => ProfileDataMode::Transient,
        }
    })
}
