namespace Fast.Web.Controllers
{
    [Authorize]
    [ApiController]
    [Route("api/[controller]")]
    public class BrokerController : ODataController
    {
        private readonly MyDbContext db;
        private readonly AuthorizationHelper authHelper;

        public BrokerController(MyDbContext context)
        {
            db = context;
            authHelper = new AuthorizationHelper(Main.IsAuthenticationEnabled);
        }

        [Permission("Broker", PermissionType.View)]
        [Route("/odata/GetBrokerItems")]
        public IActionResult GetItems(ODataQueryOptions<BrokerListItem> queryOptions, bool isExport)
        {
            queryOptions = Util.GetQueryOptionsWithConvertedDates(queryOptions);
            var itemsQueryable = GetItemsInternal();
            var items = (queryOptions.ApplyTo(itemsQueryable) as IEnumerable<BrokerListItem>)?.ToList();

            if (isExport)
                return File(Util.Excel.GetExportFileStream(items), "application/octet-stream");
            else
                return Ok(items);
        }

        [Permission("Broker", PermissionType.View)]
        [Route("[action]")]
        public IQueryable<BrokerListItem> GetItemsInternal()
        {
            IQueryable<BrokerListItem>? itemsQueryable = null;

            itemsQueryable = (
                from q in db.VwBrokerOverviewInfos
                select new BrokerListItem
                {
                    BrokerId = q.BrokerId!.Value,
                    BrokerName = q.BrokerName ?? "",
                    BrokerAccounts = q.BrokerAccounts ?? "",
                    BrokerType = q.BrokerType ?? "",
                    CommissionAfterHours = q.CommissionAfterHour,
                    CommissionPerContract = q.Commission,
                    CommissionForEFS = q.Commission4Efs,
                    Memo = q.BrokerMemo ?? ""
                }
            ).AsNoTracking();

            return itemsQueryable;
        }

        [Permission("Broker", PermissionType.View)]
        [Route("[action]")]
        public async Task<IActionResult> GetRequiredData()
        {
            var hasModifyPermission = await authHelper.IsAuthorizedAsync(User, "Broker", PermissionType.Modify);
            var brokerTypes = new[] { new { BrokerType = "General" }, new { BrokerType = "Floor" } };
            var brokerAccounts = await DataHelper.GetBrokersAsync();

            var result = new { hasModifyPermission, brokerTypes, brokerAccounts };
            return Ok(result);
        }

        [Permission("Broker", PermissionType.View)]
        [Route("[action]")]
        public async Task<IActionResult> GetDetail(int id)
        {
            var detail = await (
                from q in db.Brokers
                where q.Id == id
                select new BrokerDetail
                {
                    BrokerId = q.Id,
                    BrokerName = q.Name ?? "",
                    BrokerType = q.BrokerType ?? "",
                    CommissionAfterHours = q.CommissionAfterHour,
                    CommissionForEFS = q.Commission4Efs,
                    CommissionPerContract = q.Commission,
                    Memo = q.BrokerMemo ?? "",
                    BrokerAccounts = (from ba in db.BrokerAccounts
                                      where q.Id.ToString() == ba.BrokerId
                                      orderby ba.Name
                                      select new BrokerAccountItem
                                      {
                                          Id = ba.Id,
                                          Name = ba.Name ?? ""
                                      }).ToList()
                }
            ).AsNoTracking().FirstAsync();

            return Ok(detail);
        }

        public enum SaveType
        {
            New = 1,
            Normal = 2
        }

        [Permission("Broker", PermissionType.Modify)]
        [Route("[action]")]
        public async Task<IActionResult> SaveDetail(BrokerDetail detail, SaveType saveType)
        {
            int resultId = 0;

            await db.Database.CreateExecutionStrategy().Execute(async () =>
            {
                using var dbContextTransaction = await db.Database.BeginTransactionAsync();
                Broker? dbItem = null;
                if (saveType != SaveType.New)
                {
                    dbItem = await (
                        from q in db.Brokers
                        where q.Id == detail.BrokerId
                        select q
                    ).FirstOrDefaultAsync();
                }

                if (dbItem == null) //if the item does not exist then add it
                {
                    dbItem = new Broker();
                    db.Brokers.Add(dbItem);
                }
                else
                {
                    //remove existing items so that they get completely re-inserted
                }

                var d = detail;
                dbItem.Name = d.BrokerName;
                dbItem.BrokerType = d.BrokerType;
                dbItem.Commission = d.CommissionPerContract;
                dbItem.CommissionAfterHour = d.CommissionAfterHours;
                dbItem.Commission4Efs = d.CommissionForEFS;
                dbItem.BrokerMemo = d.Memo;

                await db.SaveChangesAsync();
                resultId = dbItem.Id;

                await dbContextTransaction.CommitAsync();
            });

            return Ok(resultId);
        }

        [Permission("Broker", PermissionType.Modify)]
        [Route("[action]/{id}")]
        public async Task<IActionResult> DeleteDetail(int id)
        {
            Broker dbItem = await db.Brokers.Where(x => x.Id == id).FirstAsync();
            db.Brokers.Remove(dbItem);
            await db.SaveChangesAsync();

            return Ok();
        }

        [Permission("Broker", PermissionType.Modify)]
        [Route("[action]/{brokerId}/{brokerAccountName}")]
        public async Task<IActionResult> AddNewBrokerAccount(int brokerId, string brokerAccountName)
        {
            var account = new BrokerAccount
            {
                BrokerId = brokerId.ToString(),
                Name = brokerAccountName
            };
            db.BrokerAccounts.Add(account);

            await db.SaveChangesAsync();

            return Ok(new { brokerAccountId = account.Id, brokerAccountName = account.Name });
        }

        [Permission("Broker", PermissionType.Modify)]
        [Route("[action]/{brokerAccountId}/{brokerAccountName}")]
        public async Task<IActionResult> RenameBrokerAccount(int brokerAccountId, string brokerAccountName)
        {
            var account = await db.BrokerAccounts.Where(x => x.Id == brokerAccountId).FirstAsync();
            account.Name = brokerAccountName;

            await db.SaveChangesAsync();

            return Ok();
        }

        [Permission("Broker", PermissionType.Modify)]
        [Route("[action]/{brokerAccountId}")]
        public async Task<IActionResult> DeleteBrokerAccount(int brokerAccountId)
        {
            var account = await db.BrokerAccounts.Where(x => x.Id == brokerAccountId).FirstAsync();
            db.BrokerAccounts.Remove(account);

            await db.SaveChangesAsync();

            return Ok();
        }

    }
}
