//! Git-panel press dispatch — extracted from `press.rs` to keep
//! that file under the repo's 800-line cap.
//!
//! The floating Git panel sits above the right-rail panels in paint
//! order; `apply_press` calls [`WidgetHostNative::dispatch_git_panel_press`]
//! after the rail blocks (which already skip a click that lands
//! inside the Git-panel rect) and before the canvas overlays.

use op_editor_core::{GitDiffTarget, GitPanelAction};
use op_editor_ui::widgets::{GitPanel, GitPanelHit};
use op_editor_ui::Point2D;

use super::WidgetHostNative;

impl WidgetHostNative {
    /// Dispatch a press inside the floating Git panel.
    ///
    /// Returns `true` when the click was consumed by the panel — a
    /// focus change or a queued `GitPanelState::pending_action`.
    /// Returns `false` when the click is outside the panel (the
    /// commit input is defocused as a side effect) so the caller
    /// keeps hit-testing.
    pub(in crate::widget_host) fn dispatch_git_panel_press(
        &mut self,
        x: f32,
        y: f32,
        viewport_width: f32,
        viewport_height: f32,
    ) -> bool {
        let Some(panel_rect) = self.git_panel_rect(viewport_width, viewport_height) else {
            return false;
        };
        // Compute everything that needs an immutable `GitPanel`
        // borrow up front — the hit, and the diff scroll bound —
        // then drop the borrow before mutating `editor_state`.
        let hit = GitPanel::for_editor(&self.editor_state)
            .and_then(|p| p.hit_test(panel_rect, Point2D::new(x, y)));
        let diff_max_scroll = GitPanel::for_editor(&self.editor_state)
            .map(|p| p.diff_max_scroll())
            .unwrap_or(0);
        let diff_max_h_scroll = GitPanel::for_editor(&self.editor_state)
            .map(|p| p.diff_max_h_scroll())
            .unwrap_or(0);
        let panel = &mut self.editor_state.editor_ui.git_panel;
        match hit {
            Some(GitPanelHit::CommitInput) => {
                panel.commit_focused = true;
                panel.remote_focused = false;
                panel.https_focused = false;
            }
            Some(GitPanelHit::RemoteInput) => {
                panel.remote_focused = true;
                panel.commit_focused = false;
                panel.https_focused = false;
            }
            Some(GitPanelHit::HttpsInput) => {
                panel.https_focused = true;
                panel.commit_focused = false;
                panel.remote_focused = false;
            }
            Some(GitPanelHit::SetRemote) => {
                if !panel.remote_draft.trim().is_empty() {
                    panel.pending_action =
                        Some(GitPanelAction::SetRemote(panel.remote_draft.clone()));
                }
            }
            Some(GitPanelHit::SetupSshAuth) => {
                panel.pending_action = Some(GitPanelAction::SetupSshAuth);
            }
            Some(GitPanelHit::SetHttpsAuth) => {
                if !panel.https_draft.trim().is_empty() {
                    panel.pending_action =
                        Some(GitPanelAction::SetHttpsAuth(panel.https_draft.clone()));
                }
            }
            Some(GitPanelHit::Commit) => {
                // Commit the staged set — requires a message and at
                // least one staged file.
                if !panel.commit_message.trim().is_empty()
                    && panel.changed_files.iter().any(|f| f.staged)
                {
                    panel.pending_action = Some(GitPanelAction::Commit);
                }
            }
            Some(GitPanelHit::Refresh) => {
                panel.pending_action = Some(GitPanelAction::Refresh);
            }
            Some(GitPanelHit::Pull) => {
                panel.pending_action = Some(GitPanelAction::Pull);
            }
            Some(GitPanelHit::Push) => {
                panel.pending_action = Some(GitPanelAction::Push);
            }
            Some(GitPanelHit::AbortMerge) => {
                panel.pending_action = Some(GitPanelAction::AbortMerge);
            }
            Some(GitPanelHit::CompleteMerge) => {
                panel.pending_action = Some(GitPanelAction::CompleteMerge);
            }
            Some(GitPanelHit::SwitchBranch(index)) => {
                if let Some(name) = panel.branches.get(index).cloned() {
                    panel.pending_action = Some(GitPanelAction::SwitchBranch(name));
                }
            }
            Some(GitPanelHit::MergeBranch(index)) => {
                if let Some(name) = panel.branches.get(index).cloned() {
                    panel.pending_action = Some(GitPanelAction::MergeBranch(name));
                }
            }
            Some(GitPanelHit::ShowWorkingDiff) => {
                panel.pending_action = Some(GitPanelAction::ShowDiff(GitDiffTarget::WorkingTree));
            }
            Some(GitPanelHit::ShowCommitDiff(index)) => {
                if let Some(rev) = panel
                    .recent_commits
                    .get(index)
                    .map(|c| c.short_hash.clone())
                {
                    panel.pending_action =
                        Some(GitPanelAction::ShowDiff(GitDiffTarget::Commit(rev)));
                }
            }
            Some(GitPanelHit::ShowFileDiff(index)) => {
                if let Some(path) = panel.conflicted_files.get(index).cloned() {
                    panel.pending_action =
                        Some(GitPanelAction::ShowDiff(GitDiffTarget::Path(path)));
                }
            }
            Some(GitPanelHit::ToggleStageFile(index)) => {
                if let Some(path) = panel.changed_files.get(index).map(|f| f.path.clone()) {
                    panel.pending_action = Some(GitPanelAction::ToggleStageFile(path));
                }
            }
            Some(GitPanelHit::ShowChangedFileDiff(index)) => {
                if let Some(path) = panel.changed_files.get(index).map(|f| f.path.clone()) {
                    panel.pending_action =
                        Some(GitPanelAction::ShowDiff(GitDiffTarget::Path(path)));
                }
            }
            Some(GitPanelHit::CloseDiff) => {
                // Pure UI state — no git op needed.
                panel.diff = None;
            }
            Some(GitPanelHit::DiffScrollUp) => {
                let step = GitPanel::diff_page_step();
                if let Some(diff) = &mut panel.diff {
                    diff.scroll = diff.scroll.saturating_sub(step);
                }
            }
            Some(GitPanelHit::DiffScrollDown) => {
                let step = GitPanel::diff_page_step();
                if let Some(diff) = &mut panel.diff {
                    diff.scroll = (diff.scroll + step).min(diff_max_scroll);
                }
            }
            Some(GitPanelHit::DiffScrollLeft) => {
                let step = GitPanel::diff_h_step();
                if let Some(diff) = &mut panel.diff {
                    diff.h_scroll = diff.h_scroll.saturating_sub(step);
                }
            }
            Some(GitPanelHit::DiffScrollRight) => {
                let step = GitPanel::diff_h_step();
                if let Some(diff) = &mut panel.diff {
                    diff.h_scroll = (diff.h_scroll + step).min(diff_max_h_scroll);
                }
            }
            Some(GitPanelHit::StageHunk(hunk)) => {
                if let Some(path) = panel.diff.as_ref().and_then(|d| d.stage_path.clone()) {
                    panel.pending_action = Some(GitPanelAction::StageHunk(path, hunk));
                }
            }
            Some(GitPanelHit::MergeChoiceOurs(index)) => {
                if let Some(merge) = &mut panel.merge_resolve {
                    merge.set_choice(index, false);
                }
            }
            Some(GitPanelHit::MergeChoiceTheirs(index)) => {
                if let Some(merge) = &mut panel.merge_resolve {
                    merge.set_choice(index, true);
                }
            }
            Some(GitPanelHit::ApplyMergeResolution) => {
                panel.pending_action = Some(GitPanelAction::ApplyMergeResolution);
            }
            Some(GitPanelHit::CancelMergeResolution) => {
                // Pure UI state — drop the resolution view, no merge.
                panel.merge_resolve = None;
            }
            Some(GitPanelHit::Inside) => {
                // Panel chrome — swallow the click + defocus inputs.
                panel.commit_focused = false;
                panel.remote_focused = false;
                panel.https_focused = false;
            }
            None => {
                // Outside the panel — release the input focus, then
                // let the click fall through.
                if panel.commit_focused || panel.remote_focused || panel.https_focused {
                    panel.commit_focused = false;
                    panel.remote_focused = false;
                    panel.https_focused = false;
                    self.mark_dirty();
                }
                return false;
            }
        }
        self.mark_dirty();
        true
    }
}
