/* 
 * Copyright (c)2009-2025 DemiVision, LLC. All Rights Reserved. The information 
 * herein is the CONFIDENTIAL and PROPRIETARY information of DemiVision, LLC. 
 */

using DXLib.UI;
using DXLib.UI.Layout;
using DXLib.UI.Container;
using DXLib.UI.Control.Button;

using DXLib.UI.Form;
using DXLib.UI.Form.Control;

using DXLib.Data;
using DXLib.Data.Model;

using DXLib.Utils;

namespace iStatVball3;

/*
 * Displays a list of tree select controls, each allowing the user to select a combination of options for a match filter
 * component (type, format, etc). The combined list of selections from all controls can be used with TagFilter to filter
 * matches for a season scope stat analysis report.
 */
public class TagFilterView : DXGridLayout
{
	/* Events */
	public Action Cleared { get; set; }
	public Action Filtered { get; set; }

	/* Fields */
	private readonly DXScroll scroll;
	private readonly DXGridLayout layout;

	// Header
	private DXGridLayout header;

	private DXButton clearBtn;
	private DXButton filterBtn;

	// Tag controls
	private readonly List<DXTreeSelect> trees;

	// Date range
	private DXPicker startPicker;
	private DXPicker endPicker;

	// Underlying data
	private Season filterSeason;

	/* Methods */
	public TagFilterView()
	{
		BackgroundColor = DXColors.Light4;

		Padding = 0;
		RowSpacing = 0;
		ColumnSpacing = 0;

		// Control layout
		layout = new DXGridLayout
		{
			BackgroundColor = DXColors.Light4,

			Padding = 20,
			RowSpacing = 20,
			ColumnSpacing = 0
		};

		// Scrollable control area
		scroll = new DXScroll
		{
			BackgroundColor = DXColors.Light4,
			Orientation = ScrollOrientation.Vertical,
			Padding = 0,

			Content = layout
		};

		// Allocate container
		trees = [];
	}

	// Post construction initialization
	public void Init( Season season )
	{
		filterSeason = season;

		AddFixedRow( 46 );
		AddStarRow();

		// Add clear/filter buttons
		CreateHeader();

		Add( header, 0, 0 );
		Add( scroll, 0, 1 );

		// Add underlying controls
		CreateControls();
	}

	// Creates button header UI
	private void CreateHeader()
	{
		// Button layout
		header = new DXGridLayout
		{
			BackgroundColor = DXColors.Light2,

			Padding = new Thickness( 20, 4, 15, 4 ),
			RowSpacing = 0,
			ColumnSpacing = 5
		};

		const double buttonWd = 69;

		// Clear
		clearBtn = new DXButton
		{
			Resource = "filter.clear",
			Type = DXButton.ButtonType.Neutral,

			Margin = new Thickness( 0, 5, 0, 0 ),
			IsDisabled = true,

			ButtonTapped = OnClearTapped
		};

		clearBtn.Init();
		
		// Filter
		filterBtn = new DXButton
		{
			Resource = "filter.filter",
			Type = DXButton.ButtonType.Action,

			Margin = new Thickness( 0, 5, 0, 0 ),
			IsDisabled = true,

			ButtonTapped = OnFilterTapped
		};

		filterBtn.Init();
		
		// 3 columns
		header.AddStarColumn();                 // 0: set
		header.AddFixedColumn( buttonWd );      // 1: delete
		header.AddFixedColumn( buttonWd );      // 2: filter

		header.Add( clearBtn, 1, 0 );
		header.Add( filterBtn, 2, 0 );
	}

	// Adds all filter controls
	private void CreateControls()
	{
		// Tags
		AddMatch();
		AddOpponent();
		AddTournament();
		AddType();
		AddResult();
		AddFormat();
		AddLeague();
		AddHome();
		AddStatistician();
		AddVenue();

		// Date range
		AddDateRange();
	}

	// (Re)sets selected state of all filter controls
	public void Reset()
	{
		// Select all filters
		foreach ( DXTreeSelect tree in trees )
		{
			tree.SelectAll();
		}

		// Full date range
		ResetDates();

		// Buttons not valid yet
		clearBtn.IsDisabled = true;
		filterBtn.IsDisabled = true;
	}

	// Resets season start/end date range
	private void ResetDates()
	{
		startPicker.SetDate( filterSeason.GetStartDate().DateTime );
		endPicker.SetDate( filterSeason.GetEndDate().DateTime );
	}

	/* Add */

	// Adds control for filtering by Match
	private void AddMatch()
	{
		AddTree( "match", "match.singular" );

		List<DXModel> matches = filterSeason.Matches.Cast<DXModel>().ToList();

		// Sort by date
		List<DXModel> sorted = matches.OrderByDescending( m => m.Created ).ToList();

		// Populate tree
		PopulateModels( MatchTree, sorted, false );
	}

	// Adds control for filtering by Opponent
	private void AddOpponent()
	{
		AddTree( "opponent", "match.opp" );

		List<DXModel> opponents = filterSeason.Opponents.Cast<DXModel>().ToList();

		// Populate tree
		PopulateModels( OpponentTree, opponents );

		// Might be empty
		OpponentTree.IsDisabled = (opponents.Count == 0);
	}

	// Adds control for filtering by Tournament
	private void AddTournament()
	{
		AddTree( "tournament", "match.tourn" );

		List<DXModel> tournaments = filterSeason.Tournaments.Cast<DXModel>().ToList();

		// Populate tree
		PopulateModels( TournamentTree, tournaments );

		// Might be empty
		TournamentTree.IsDisabled = (tournaments.Count == 0);
	}

	// Adds control for filtering by Match Type
	private void AddType()
	{
		AddTree( "type", "match.type" );

		PopulateItems( TypeTree, "match.type" );

		bool include = Shell.Settings.AnalyzeScrimmage;

		// (De)select scrimmage type based on current setting
		TypeTree.SelectItem( Match.ScrimmageKey, include );
	}

	// Adds control for filtering by Match Result
	private void AddResult()
	{
		AddTree( "result", "match.result" );

		PopulateItems( ResultTree, "match.result" );
	}

	// Adds control for filtering by Score Format
	private void AddFormat()
	{
		AddTree( "format", "match.format" );

		PopulateItems( FormatTree, "match.format" );
	}

	// Adds control for filtering by League
	private void AddLeague()
	{
		AddTree( "league", "match.league" );

		PopulateItems( LeagueTree, "match.league" );
	}

	// Adds control for filtering by Home/Away
	private void AddHome()
	{
		AddTree( "home", "match.home" );

		PopulateItems( HomeTree, "match.home" );
	}

	// Adds control for filtering by Statistician
	private void AddStatistician()
	{
		AddTree( "statistician", "match.stat" );

		List<DXModel> statisticians = filterSeason.Statisticians.Cast<DXModel>().ToList();

		// Populate tree
		PopulateModels( StatisticianTree, statisticians );

		// Might be empty
		StatisticianTree.IsDisabled = (statisticians.Count == 0);
	}

	// Adds control for filtering by Venue
	private void AddVenue()
	{
		AddTree( "venue", "match.venue" );

		List<DXModel> venues = filterSeason.Venues.Cast<DXModel>().ToList();

		// Populate tree
		PopulateModels( VenueTree, venues );

		// Might be empty
		VenueTree.IsDisabled = (venues.Count == 0);
	}

	// Creates and adds individual tree control
	private void AddTree( string key, string title )
	{
		string titleStr = DXString.Get( title );

		// Create
		DXTreeSelect tree = new()
		{
			Key = key,

			IsRequired = true,
			Title = title,

			Label = titleStr,
			IsPlural = true,
			MaxDisplay = 2,

			Selected = OnSelected
		};

		tree.Init();
		tree.SetRoot( key, titleStr );

		trees.Add( tree );

		layout.AddFixedRow( 50 );
		layout.Add( tree, 0, (layout.RowCount - 1) );
	}

	// Adds start/end date range controls
	private void AddDateRange()
	{
		// Start date
		startPicker = new DXPicker()
		{
			Key = "start",
			Title = "season.start",
			Type = DXPicker.PickerType.Date,
			Hint = DXFormControl.HintType.None,
			Help = null,

			ControlChanged = OnSelected
		};

		startPicker.Init();
		startPicker.SetState( DXFormControl.ControlState.Normal );

		layout.AddFixedRow( 50 );
		layout.Add( startPicker, 0, layout.RowIndex );

		// End date
		endPicker = new DXPicker()
		{
			Key = "end",
			Title = "season.end",
			Type = DXPicker.PickerType.Date,
			Hint = DXFormControl.HintType.None,
			Help = null,

			ControlChanged = OnSelected
		};

		endPicker.Init();
		endPicker.SetState( DXFormControl.ControlState.Normal );

		layout.AddFixedRow( 50 );
		layout.Add( endPicker, 0, layout.RowIndex );

		// Set initial range
		ResetDates();
	}

	/* Populate */

	// Populates and configures specified tree with given data
	private static void PopulateModels( DXTreeSelect tree, List<DXModel> models, bool sort = true )
	{
		// Populate
		tree.SetChildModels( models, sort );

		// Config
		tree.SelectAll();
		tree.SetState( DXFormControl.ControlState.Normal );
	}

	// Populates and configures specified tree with given item data
	private static void PopulateItems( DXTreeSelect tree, string baseKey )
	{
		List<DXItem> items = DXString.GetLookupList( baseKey );

		// Populate
		tree.SetChildItems( items );

		// Config
		tree.SelectAll();
		tree.SetState( DXFormControl.ControlState.Normal );
	}

	/* Convenience Accessors */

	// Get Tree
	private DXTreeSelect MatchTree => GetTree( "match" );
	private DXTreeSelect OpponentTree => GetTree( "opponent" );
	private DXTreeSelect TournamentTree => GetTree( "tournament" );
	private DXTreeSelect TypeTree => GetTree( "type" );
	private DXTreeSelect ResultTree => GetTree( "result" );
	private DXTreeSelect FormatTree => GetTree( "format" );
	private DXTreeSelect LeagueTree => GetTree( "league" );
	private DXTreeSelect HomeTree => GetTree( "home" );
	private DXTreeSelect StatisticianTree => GetTree( "statistician" );
	private DXTreeSelect VenueTree => GetTree( "venue" );

	// Returns tree control matching specified key
	private DXTreeSelect GetTree( string key )
	{
		return trees.FirstOrDefault( tree => tree.Key == key );
	}

	/* Filter */

	// Returns filter object populated will all current selections
	public TagFilter GetFilter()
	{
		return new TagFilter
		{
			// Tags
			Matches = new FilterDimension( MatchTree ),
			Opponents = new FilterDimension( OpponentTree ),
			Tournaments = new FilterDimension( TournamentTree ),
			Types = new FilterDimension( TypeTree ),
			Results = new FilterDimension( ResultTree ),
			Formats = new FilterDimension( FormatTree ),
			Leagues = new FilterDimension( LeagueTree ),
			Homes = new FilterDimension( HomeTree ),
			Statisticians = new FilterDimension( StatisticianTree ),
			Venues = new FilterDimension( VenueTree ),

			// Date range
			StartDate = startPicker.GetDate(),
			EndDate = endPicker.GetDate()
		};
	}

	/* Event Callbacks */

	// User changed selection, clear/filter now valid
	private void OnSelected()
	{
		clearBtn.IsDisabled = false;
		filterBtn.IsDisabled = false;
	}

	// User wants to clear all filter selections
	private void OnClearTapped( object sender )
	{
		// Default to everything selected
		Reset();

		// Callback listener
		Cleared?.Invoke();
	}

	// User tapped filter
	private void OnFilterTapped( object sender )
	{
		// Filter no longer valid until modified
		filterBtn.IsDisabled = true;

		// Callback listener
		Filtered?.Invoke();
	}
}

//
