#![allow(
	dead_code,
	clippy::missing_const_for_fn,
	clippy::unused_self
)]

use std::path::PathBuf;

use crate::{
	components::{
		visibility_blocking, CommandBlocking, CommandInfo, Component,
		DrawableComponent, EventState, RevisionFilesComponent,
	},
	keys::SharedKeyConfig,
	queue::Queue,
	ui::style::SharedTheme,
	AsyncAppNotification, AsyncNotification,
};
use anyhow::Result;
use asyncgit::{sync, CWD};
use crossbeam_channel::Sender;

pub struct FilesTab {
	visible: bool,
	theme: SharedTheme,
	key_config: SharedKeyConfig,
	files: RevisionFilesComponent,
}

impl FilesTab {
	///
	pub fn new(
		sender: &Sender<AsyncAppNotification>,
		queue: &Queue,
		theme: SharedTheme,
		key_config: SharedKeyConfig,
	) -> Self {
		Self {
			visible: false,
			files: RevisionFilesComponent::new(
				queue,
				sender,
				theme.clone(),
				key_config.clone(),
			),
			theme,
			key_config,
		}
	}

	///
	pub fn update(&mut self) -> Result<()> {
		if self.is_visible() {
			if let Ok(head) = sync::get_head(CWD) {
				self.files.set_commit(head)?;
			}
		}

		Ok(())
	}

	///
	pub fn anything_pending(&self) -> bool {
		self.files.any_work_pending()
	}

	///
	pub fn update_async(&mut self, ev: AsyncNotification) {
		if self.is_visible() {
			self.files.update(ev);
		}
	}

	pub fn file_finder_update(&mut self, file: &Option<PathBuf>) {
		self.files.find_file(file);
	}
}

impl DrawableComponent for FilesTab {
	fn draw<B: tui::backend::Backend>(
		&self,
		f: &mut tui::Frame<B>,
		rect: tui::layout::Rect,
	) -> Result<()> {
		if self.is_visible() {
			self.files.draw(f, rect)?;
		}
		Ok(())
	}
}

impl Component for FilesTab {
	fn commands(
		&self,
		out: &mut Vec<CommandInfo>,
		force_all: bool,
	) -> CommandBlocking {
		if self.visible || force_all {
			return self.files.commands(out, force_all);
		}

		visibility_blocking(self)
	}

	fn event(
		&mut self,
		ev: crossterm::event::Event,
	) -> Result<EventState> {
		if self.visible {
			return self.files.event(ev);
		}

		Ok(EventState::NotConsumed)
	}

	fn is_visible(&self) -> bool {
		self.visible
	}

	fn hide(&mut self) {
		self.visible = false;
	}

	fn show(&mut self) -> Result<()> {
		self.visible = true;
		self.update()?;
		Ok(())
	}
}
