using System.Linq.Expressions;
using Microsoft.AspNetCore.Mvc;
using Strata.Code.Business.Services.Interfaces;
using Strata.Code.DataAccess.Models;

namespace Strata.Code.Web.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class BudgetConfigDefaultSettingController : ControllerBase
    {
        private readonly IBudgetConfigDefaultSettingService _service;

        public BudgetConfigDefaultSettingController(IBudgetConfigDefaultSettingService service)
        {
            _service = service ?? throw new ArgumentNullException(nameof(service));
        }

        [HttpGet]
        [ProducesResponseType(typeof(IEnumerable<BudgetConfigDefaultSettingDto>), StatusCodes.Status200OK)]
        public async Task<IActionResult> GetAll()
        {
            var settings = await _service.GetAllAsync();
            return Ok(settings);
        }

        [HttpGet("{id}")]
        [ProducesResponseType(typeof(BudgetConfigDefaultSettingDto), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<IActionResult> GetById(int id)
        {
            var setting = await _service.GetByIdAsync(id);
            if (setting == null)
                return NotFound();

            return Ok(setting);
        }

        [HttpPost]
        [ProducesResponseType(typeof(BudgetConfigDefaultSettingDto), StatusCodes.Status201Created)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Create([FromBody] BudgetConfigDefaultSettingDto setting)
        {
            if (!ModelState.IsValid)
                return BadRequest(ModelState);

            var createdSetting = await _service.CreateAsync(setting);
            return CreatedAtAction(nameof(GetById), new { id = createdSetting.SettingId }, createdSetting);
        }

        [HttpPut("{id}")]
        [ProducesResponseType(typeof(BudgetConfigDefaultSettingDto), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Update(int id, [FromBody] BudgetConfigDefaultSettingDto setting)
        {
            if (id != setting.SettingId)
                return BadRequest();

            var updatedSetting = await _service.UpdateAsync(setting);
            if (updatedSetting == null)
                return NotFound();

            return Ok(updatedSetting);
        }

        [HttpDelete("{id}")]
        [ProducesResponseType(StatusCodes.Status204NoContent)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<IActionResult> Delete(int id)
        {
            var result = await _service.DeleteAsync(id);
            if (!result)
                return NotFound();

            return NoContent();
        }

        [HttpGet("byname/{name}")]
        [ProducesResponseType(typeof(IEnumerable<BudgetConfigDefaultSettingDto>), StatusCodes.Status200OK)]
        public async Task<IActionResult> GetByName(string name)
        {
            var settings = await _service.GetByNameAsync(name);
            return Ok(settings);
        }

        [HttpPost("byids")]
        [ProducesResponseType(typeof(IEnumerable<BudgetConfigDefaultSettingDto>), StatusCodes.Status200OK)]
        public async Task<IActionResult> GetByIds([FromBody] IEnumerable<int> ids)
        {
            var settings = await _service.GetByIdsAsync(ids);
            return Ok(settings);
        }

        [HttpPost("search")]
        [ProducesResponseType(typeof(IEnumerable<BudgetConfigDefaultSettingDto>), StatusCodes.Status200OK)]
        public async Task<IActionResult> FindBy([FromBody] string predicateExpression)
        {
            // Note: In a real implementation, you'd want to create a more structured search model
            // This is just an example of how you might expose the FindBy functionality
            var predicate = BuildPredicate(predicateExpression);
            var settings = await _service.FindByAsync(predicate);
            return Ok(settings);
        }

        private Expression<Func<BudgetConfigDefaultSetting, bool>> BuildPredicate(string expression)
        {
            // This is a simplified example - in practice, you'd want to implement
            // a more robust expression parser or use a different approach for searching
            return setting => setting.Name.Contains(expression) ||
                            setting.Description.Contains(expression);
        }
    }
}
