using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using WpfEngineeringSketch.Commands;
using WpfEngineeringSketch.Models.Scene;
using WpfEngineeringSketch.Tools3D;

namespace WpfEngineeringSketch.ViewModels
{
    public class MainViewModel : ViewModelBase
    {
        private BlockType _selectedBlockType;
        private SceneObject? _selectedObject;
        private I3DTool _currentTool = null!;

        public ObservableCollection<SceneObject> Objects { get; } = new ObservableCollection<SceneObject>();

        // Expose all block types for the ComboBox
        public IEnumerable<BlockType> BlockTypes { get; } = Enum.GetValues<BlockType>();

        public BlockType SelectedBlockType
        {
            get => _selectedBlockType;
            set
            {
                if (SetProperty(ref _selectedBlockType, value))
                {
                    // Auto-switch to Place Tool for building types unless already path-building
                    if ((value == BlockType.CMUWall || value == BlockType.Column || value == BlockType.Beam || value == BlockType.Connection)
                        && !(CurrentTool is PathTool3D))
                    {
                        CurrentTool = new PlaceTool3D();
                    }
                }
            }
        }

        public ObservableCollection<SceneObject> SelectedObjects { get; } = new ObservableCollection<SceneObject>();

        public SceneObject? SelectedObject
        {
            get => _selectedObject;
            set => SetProperty(ref _selectedObject, value);
        }

        private bool _showSmartPlacementHints = true;
        public bool ShowSmartPlacementHints
        {
            get => _showSmartPlacementHints;
            set => SetProperty(ref _showSmartPlacementHints, value);
        }

        public I3DTool CurrentTool
        {
            get => _currentTool;
            set
            {
                if (_currentTool != value)
                {
                    _currentTool?.Deactivate(this);
                    _currentTool = value;
                    _currentTool?.Activate(this);
                    OnPropertyChanged();
                }
            }
        }

        public ICommand AddBlockCommand { get; }
        public ICommand DeleteBlockCommand { get; }
        public ICommand SelectToolCommand { get; }
        public ICommand PathToolCommand { get; }
        public ICommand PlaceToolCommand { get; }
        public ICommand MoveToolCommand { get; }
        public ICommand AddWallOnGridCommand { get; }

        public MainViewModel()
        {
            AddBlockCommand = new RelayCommand(_ => AddBlock());
            DeleteBlockCommand = new RelayCommand(_ => DeleteBlock());
            AddWallOnGridCommand = new RelayCommand(_ => AddWallOnGrid());

            SelectToolCommand = new RelayCommand(_ => CurrentTool = new SelectTool3D());
            PathToolCommand = new RelayCommand(_ => CurrentTool = new PathTool3D());
            PlaceToolCommand = new RelayCommand(_ => ExecutePlaceOrBuild());
            MoveToolCommand = new RelayCommand(_ => CurrentTool = new MoveTool3D());

            // Default tool
            CurrentTool = new SelectTool3D();

            // Add a sample object
            Objects.Add(new SceneObject { Type = BlockType.Cube, Position = new Point3D(0, 0.5, 0) });

            // Add sample grid lines
            // Line along X
            Objects.Add(new SceneObject { Type = BlockType.GridLine, Position = new Point3D(0, 0, 5), Rotation = new Vector3D(0, 0, 90), Scale = new Vector3D(1, 1, 1) });
            // Line along Z
            Objects.Add(new SceneObject { Type = BlockType.GridLine, Position = new Point3D(5, 0, 0), Rotation = new Vector3D(90, 0, 0), Scale = new Vector3D(1, 1, 1) });
            // Intersecting lines at origin
            Objects.Add(new SceneObject { Type = BlockType.GridLine, Position = new Point3D(0, 0, 0), Rotation = new Vector3D(0, 0, 90) });
            Objects.Add(new SceneObject { Type = BlockType.GridLine, Position = new Point3D(0, 0, 0), Rotation = new Vector3D(90, 0, 0) });
        }

        private void AddWallOnGrid()
        {
            foreach (var obj in SelectedObjects.ToList())
            {
                if (obj.Type == BlockType.GridLine)
                {
                    var wall = new SceneObject
                    {
                        Type = BlockType.CMUWall,
                        Position = obj.Position,
                    };
                    Objects.Add(wall);
                }
            }
        }

        private void AddBlock()
        {
            var newObj = new SceneObject
            {
                Type = SelectedBlockType,
                Position = new Point3D(0, 2, 0)
            };
            Objects.Add(newObj);
            SelectedObject = newObj;
        }

        private void DeleteBlock()
        {
            if (SelectedObject != null)
            {
                Objects.Remove(SelectedObject);
                SelectedObject = null;
            }
        }

        private void ExecutePlaceOrBuild()
        {
            if (CurrentTool is PathTool3D && SelectedObjects.Any(o => o.Type == BlockType.GridLine))
            {
                AddWallOnGrid();
                foreach (var obj in SelectedObjects.ToList()) obj.IsSelected = false;
                SelectedObjects.Clear();
            }
            else
            {
                CurrentTool = new PlaceTool3D();
            }
        }
    }
}
