using Blahblah.FlowerStory.Server.Data;
using Blahblah.FlowerStory.Server.Data.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging.Abstractions;
using System.ComponentModel.DataAnnotations;
using System.Runtime.InteropServices;
namespace Blahblah.FlowerStory.Server.Controller;
/// 
/// 花草相关 API 服务
/// 
[ApiController]
[Produces("application/json")]
[Route("api/flower")]
public class FlowerApiController : BaseController
{
    /// 
    public FlowerApiController(FlowerDatabase database, ILogger? logger = null) : base(database, logger)
    {
    }
    /// 
    /// 获取用户名下所有符合条件的花草
    /// 
    /// 
    /// 请求示例:
    /// 
    ///     GET /api/flower/query
    ///     Authorization: authorization id
    /// 
    /// 参数:
    /// 
    ///     cid: int?
    ///     key: string?
    ///     from: long?
    ///     to: long?
    ///     cfrom: decimal?
    ///     cto: decimal?
    ///     photo: bool?
    ///     lon: double?
    ///     lat: double?
    ///     distance: int?
    ///     p: int?
    ///     size: int?
    /// 
    /// 
    /// 类别 id
    /// 查询关键字
    /// 起始购买日期
    /// 结束购买日期
    /// 开销最小值
    /// 开销最大值
    /// 是否包含封面图片
    /// 纬度
    /// 经度
    /// 距离(米)
    /// 页数
    /// 分页大小
    /// 会话有效则返回符合条件的花草集
    /// 返回符合条件的花草集
    /// 未找到登录会话或已过期
    /// 用户已禁用
    /// 未找到关联用户
    [Route("query", Name = "queryFlowers")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet]
    [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
    public ActionResult GetFlowers(
        [FromQuery(Name = "cid")] int? categoryId,
        [FromQuery] string? key,
        [FromQuery(Name = "from")] long? buyFrom,
        [FromQuery(Name = "to")] long? buyTo,
        [FromQuery(Name = "cfrom")] decimal? costFrom,
        [FromQuery(Name = "cto")] decimal? costTo,
        [FromQuery(Name = "photo")] bool? includePhoto,
        [FromQuery(Name = "lat")] double? latitude,
        [FromQuery(Name = "lon")] double? longitude,
        [FromQuery] int? distance,
        [FromQuery(Name = "p")] int? page = 0,
        [FromQuery(Name = "size")] int? pageSize = 20)
    {
        var (result, user) = CheckPermission();
        if (result != null)
        {
            return result;
        }
        if (user == null)
        {
            return NotFound();
        }
        SaveDatabase();
        IEnumerable flowers = database.Flowers.Where(f => f.OwnerId == user.Id);
        if (categoryId != null)
        {
            flowers = flowers.Where(f => f.CategoryId == categoryId);
        }
        if (key != null)
        {
            flowers = flowers.Where(f =>
                f.Name.ToLower().Contains(key.ToLower()) ||
                f.Purchase != null &&
                f.Purchase.ToLower().Contains(key.ToLower()));
        }
        if (buyFrom != null)
        {
            flowers = flowers.Where(f => f.DateBuyUnixTime >= buyFrom);
        }
        if (buyTo != null)
        {
            flowers = flowers.Where(f => f.DateBuyUnixTime <= buyTo);
        }
        if (costFrom != null)
        {
            flowers = flowers.Where(f => f.Cost != null && f.Cost >= costFrom);
        }
        if (costTo != null)
        {
            flowers = flowers.Where(f => f.Cost != null && f.Cost <= costTo);
        }
        if (distance != null && latitude != null && longitude != null)
        {
            flowers = flowers.Where(f => f.Latitude != null && f.Longitude != null)
                .AsEnumerable()
                .Where(f =>
                {
                    var d = GetDistance(latitude.Value, longitude.Value, f.Latitude ?? 0, f.Longitude ?? 0);
                    f.Distance = (int)d;
                    return d <= distance;
                });
        }
        int count = flowers.Count();
        var size = pageSize ?? 20;
        var p = page ?? 0;
        flowers = flowers.OrderByDescending(f => f.DateBuyUnixTime).Skip(p * size).Take(size);
        if (includePhoto == true)
        {
            foreach (var f in flowers)
            {
                f.Photos = database.Photos.Where(p =>
                    database.Records.Any(r =>
                        r.FlowerId == f.Id && r.EventId == EventCover && r.Id == p.RecordId)).ToList();
                foreach (var photo in f.Photos)
                {
                    photo.Url = $"photo/flower/{f.Id}/{photo.Path}";
                }
            }
        }
        return Ok(new FlowerResult
        {
            Flowers = flowers.ToArray(),
            Count = count
        });
    }
    /// 
    /// 查询用户的花草
    /// 
    /// 
    /// 请求示例:
    /// 
    ///     GET /api/flower/get
    ///     Authorization: authorization id
    /// 
    /// 参数:
    /// 
    ///     id: int
    ///     photo: bool?
    /// 
    /// 
    /// 花草唯一 id
    /// 是否包含封面图片
    /// 会话有效则返回查询到的花草对象
    /// 返回查询到的花草对象
    /// 未找到登录会话或已过期
    /// 用户已禁用
    /// 未找到关联用户或者未找到花草
    [Route("get", Name = "getFlower")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet]
    [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
    public ActionResult GetFlower(
        [FromQuery][Required] int id,
        [FromQuery(Name = "photo")] bool? includePhoto)
    {
        var (result, user) = CheckPermission();
        if (result != null)
        {
            return result;
        }
        if (user == null)
        {
            return NotFound();
        }
        SaveDatabase();
        var item = database.Flowers.Find(id);
        if (item == null)
        {
            return NotFound($"Flower id {id} not found");
        }
        if (includePhoto == true)
        {
            item.Photos = database.Photos.Where(p =>
                database.Records.Any(r =>
                    r.FlowerId == item.Id && r.EventId == EventCover && r.Id == p.RecordId)).ToList();
            foreach (var photo in item.Photos)
            {
                photo.Url = $"photo/flower/{item.Id}/{photo.Path}";
            }
        }
        return Ok(item);
    }
    /// 
    /// 移除用户的花草
    /// 
    /// 
    /// 请求示例:
    /// 
    ///     DELETE /api/flower/remove
    ///     Authorization: authorization id
    /// 
    /// 参数:
    /// 
    ///     id: int
    /// 
    /// 
    /// 花草唯一 id
    /// 会话有效则返回操作影响的数据库行数
    /// 返回操作影响的数据库行数
    /// 未找到登录会话或已过期
    /// 用户已禁用
    /// 未找到关联用户
    [Route("remove", Name = "removeFlower")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpDelete]
    public ActionResult RemoveFlower([FromQuery][Required] int id)
    {
        var (result, user) = CheckPermission();
        if (result != null)
        {
            return result;
        }
        if (user == null)
        {
            return NotFound();
        }
        //database.Records.Where(r => r.OwnerId == user.Id && r.FlowerId == id).ExecuteDelete();
        var count = database.Flowers.Where(f => f.OwnerId == user.Id && f.Id == id).ExecuteDelete();
        SaveDatabase();
        return Ok(count);
    }
    /// 
    /// 批量移除用户的花草
    /// 
    /// 
    /// 请求示例:
    /// 
    ///     POST /api/flower/remove
    ///     Authorization: authorization id
    ///     [
    ///         2, 4, 5, 11
    ///     ]
    /// 
    /// 
    /// 要移除的花草唯一 id 的数组
    /// 会话有效则返回操作影响的数据库行数
    /// 返回操作影响的数据库行数
    /// 未找到登录会话或已过期
    /// 用户已禁用
    /// 未找到关联用户
    [Route("removeany", Name = "removeFlowers")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpPost]
    [Consumes("application/json")]
    public ActionResult RemoveFlower([FromBody] int[] ids)
    {
        var (result, user) = CheckPermission();
        if (result != null)
        {
            return result;
        }
        if (user == null)
        {
            return NotFound();
        }
        //database.Records.Where(r => r.OwnerId == user.Id && ids.Contains(r.FlowerId)).ExecuteDelete();
        var count = database.Flowers.Where(f => f.OwnerId == user.Id && ids.Contains(f.Id)).ExecuteDelete();
        SaveDatabase();
        return Ok(count);
    }
    /// 
    /// 用户添加花草
    /// 
    /// 
    /// 请求示例:
    /// 
    ///     POST /api/flower/add
    ///     Authorization: authorization id
    /// 
    /// 参数:
    /// 
    ///     categoryId: 0
    ///     name: "玛格丽特"
    ///     dateBuy: 1684919954743
    ///     cost: 5.00
    ///     purchase: "花鸟市场"
    ///     cover: <photo>
    /// 
    /// 
    /// 花草参数
    /// 添加成功则返回已添加的花草对象
    /// 返回已添加的花草对象
    /// 未找到登录会话或已过期
    /// 用户已禁用
    /// 未找到关联用户
    /// 提交正文过大
    [Route("add", Name = "addFlower")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status413PayloadTooLarge)]
    [HttpPost]
    [Consumes("multipart/form-data")]
    [RequestSizeLimit(5 * 1024 * 1024)]
    public async Task> AddFlower([FromForm] FlowerParameter flower)
    {
        var (result, user) = CheckPermission();
        if (result != null)
        {
            return result;
        }
        if (user == null)
        {
            return NotFound();
        }
        var item = new FlowerItem
        {
            OwnerId = user.Id,
            CategoryId = flower.CategoryId,
            Name = flower.Name,
            DateBuyUnixTime = flower.DateBuy,
            Cost = flower.Cost,
            Purchase = flower.Purchase
        };
        database.Flowers.Add(item);
        SaveDatabase();
        if (flower.Cover?.Length > 0)
        {
            var file = WrapFormFile(flower.Cover);
            if (file == null)
            {
                return BadRequest();
            }
            var now = user.ActiveDateUnixTime ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            var record = database.Records.SingleOrDefault(r => r.FlowerId == item.Id && r.EventId == EventCover);
            if (record == null)
            {
                record = new RecordItem
                {
                    OwnerId = user.Id,
                    FlowerId = item.Id,
                    EventId = EventCover,
                    DateUnixTime = now,
                    ByUserId = user.Id,
                    ByUserName = user.Name
                    //Memo = ""
                };
                database.Records.Add(record);
            }
            SaveDatabase();
            try
            {
                await ExecuteTransaction(async token =>
                {
                    var cover = new PhotoItem
                    {
                        FlowerId = item.Id,
                        RecordId = record.Id,
                        FileType = file.FileType,
                        FileName = file.Filename,
                        Path = file.Path,
                        DateUploadUnixTime = now
                    };
                    AddPhotoItem(cover);
                    await WriteToFile(item.Id, file, token);
                });
            }
            catch (Exception ex)
            {
                return Problem(ex.ToString(), "api/flower/add");
                // TODO: Logger
            }
        }
        return Ok(item);
    }
    /// 
    /// 修改花草
    /// 
    /// 
    /// 请求示例:
    /// 
    ///     PUT /api/flower/update
    ///     Authorization: authorization id
    /// 
    /// 参数:
    /// 
    ///     id: 0
    ///     categoryId: 1
    ///     name: "姬小菊"
    ///     dateBuy: 1684935276117
    ///     cost: 15.40
    ///     purchase: null
    ///     cover: <photo>
    /// 
    /// 
    /// 修改参数
    /// 修改成功则返回已修改的花草对象
    /// 返回已修改的花草对象
    /// 未找到登录会话或已过期
    /// 用户已禁用
    /// 未找到关联用户或者未找到将修改的花草对象
    /// 提交正文过大
    [Route("update", Name = "updateFlower")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status413PayloadTooLarge)]
    [HttpPut]
    [Consumes("multipart/form-data")]
    [RequestSizeLimit(5 * 1024 * 1024)]
    public async Task> Update([FromForm] FlowerUpdateParameter update)
    {
        var (result, user) = CheckPermission();
        if (result != null)
        {
            return result;
        }
        if (user == null)
        {
            return NotFound();
        }
        var flower = database.Flowers.SingleOrDefault(f => f.Id == update.Id && f.OwnerId == user.Id);
        if (flower == null)
        {
            return NotFound($"Flower id {update.Id} not found");
        }
        flower.CategoryId = update.CategoryId;
        flower.Name = update.Name;
        flower.DateBuyUnixTime = update.DateBuy;
        flower.Cost = update.Cost;
        flower.Purchase = update.Purchase;
        if (update.Cover?.Length > 0)
        {
            var file = WrapFormFile(update.Cover);
            if (file == null)
            {
                return BadRequest();
            }
            var now = user.ActiveDateUnixTime ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            var record = database.Records.SingleOrDefault(r => r.FlowerId == update.Id && r.EventId == EventCover);
            if (record == null)
            {
                record = new RecordItem
                {
                    OwnerId = user.Id,
                    FlowerId = update.Id,
                    EventId = EventCover,
                    DateUnixTime = now,
                    ByUserId = user.Id,
                    ByUserName = user.Name
                    //Memo = ""
                };
                database.Records.Add(record);
            }
            else
            {
                var photos = database.Photos.Where(p => p.RecordId == record.Id).ToList();
                if (photos.Count > 0)
                {
                    database.Photos.Where(p => p.RecordId == record.Id).ExecuteDelete();
                    foreach (var photo in photos)
                    {
                        DeleteFile(update.Id, photo.Path);
                    }
                }
            }
            SaveDatabase();
            try
            {
                await ExecuteTransaction(async token =>
                {
                    var cover = new PhotoItem
                    {
                        FlowerId = update.Id,
                        RecordId = record.Id,
                        FileType = file.FileType,
                        FileName = file.Filename,
                        Path = file.Path,
                        DateUploadUnixTime = now
                    };
                    AddPhotoItem(cover);
                    await WriteToFile(update.Id, file, token);
                });
            }
            catch (Exception ex)
            {
                return Problem(ex.ToString(), "api/flower/update");
                // TODO: Logger
            }
        }
        else
        {
            SaveDatabase();
        }
        return Ok(flower);
    }
    /// 
    /// 添加花草封面
    /// 
    /// 
    /// 请求示例:
    /// 
    ///     POST /api/flower/add_cover
    ///     Authorization: authorization id
    /// 
    /// 参数:
    /// 
    ///     id: int
    ///     photo: IFormFile
    /// 
    /// 
    /// 花草唯一 id
    /// 封面图片
    /// 修改成功则返回 HTTP 204
    /// 修改成功
    /// 照片格式非法
    /// 未找到登录会话或已过期
    /// 用户已禁用
    /// 未找到关联用户或者关联的花草
    /// 提交正文过大
    [Route("add_cover", Name = "addFlowerCover")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status413PayloadTooLarge)]
    [HttpPost]
    [Consumes("multipart/form-data")]
    [RequestSizeLimit(5 * 1024 * 1024)]
    public async Task UploadCovers([Required][FromQuery] int id, [Required] IFormFile photo)
    {
        var (result, user) = CheckPermission();
        if (result != null)
        {
            return result;
        }
        if (user == null)
        {
            return NotFound();
        }
        var flower = database.Flowers.SingleOrDefault(f => f.Id == id && f.OwnerId == user.Id);
        if (flower == null)
        {
            return NotFound($"Flower id {id} not found");
        }
        if (photo.Length > 0)
        {
            var file = WrapFormFile(photo);
            if (file == null)
            {
                return BadRequest();
            }
            var now = user.ActiveDateUnixTime ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            var record = database.Records.SingleOrDefault(r => r.FlowerId == id && r.EventId == EventCover);
            if (record == null)
            {
                record = new RecordItem
                {
                    OwnerId = user.Id,
                    FlowerId = id,
                    EventId = EventCover,
                    DateUnixTime = now,
                    ByUserId = user.Id,
                    ByUserName = user.Name
                    //Memo = ""
                };
                database.Records.Add(record);
            }
            SaveDatabase();
            try
            {
                await ExecuteTransaction(async token =>
                {
                    var cover = new PhotoItem
                    {
                        FlowerId = id,
                        RecordId = record.Id,
                        FileType = file.FileType,
                        FileName = file.Filename,
                        Path = file.Path,
                        DateUploadUnixTime = now
                    };
                    AddPhotoItem(cover);
                    await WriteToFile(id, file, token);
                });
            }
            catch (Exception ex)
            {
                return Problem(ex.ToString(), "api/flower/add_cover");
                // TODO: Logger
            }
        }
        return NoContent();
    }
    /// 
    /// 获取花草特定类型事件的照片列表
    /// 
    /// 
    /// 请求示例:
    /// 
    ///     GET /api/flower/photos
    ///     Authorization: authorization id
    /// 
    /// 参数:
    /// 
    ///     id: int
    ///     eid: int?
    /// 
    /// 
    /// 花草唯一 id
    /// 事件类型 id, 0 为封面
    /// 验证通过则返回花草特定类型事件的照片列表
    /// 返回花草特定类型事件的照片列表
    /// 未找到登录会话或已过期
    /// 用户已禁用
    /// 未找到关联用户或者未找到花草对象
    [Route("photos", Name = "getFlowerPhotos")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [HttpGet]
    [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
    public ActionResult GetCovers([Required][FromQuery] int id, [FromQuery(Name = "eid")] int? eventId = 0)
    {
        var (result, user) = CheckPermission();
        if (result != null)
        {
            return result;
        }
        if (user == null)
        {
            return NotFound();
        }
        SaveDatabase();
        var photos = database.Photos.Where(p => database.Records.Any(r => r.FlowerId == id && r.EventId == eventId && r.OwnerId == user.Id));
        return Ok(photos);
    }
}