package shop.alien.store.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import shop.alien.entity.result.R;
import shop.alien.entity.store.dto.UserReservationDTO;
import shop.alien.entity.store.vo.UserReservationVo;
import shop.alien.store.service.UserReservationService;
import shop.alien.store.service.ReservationOrderPaymentTimeoutService;
import shop.alien.store.vo.ReservationOrderDetailVo;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 用户预约 前端控制器
 *
 * @author system
 */
@Slf4j
@Api(tags = {"用户预约"})
@CrossOrigin
@RestController
@RequestMapping("/user/reservation")
@RequiredArgsConstructor
public class UserReservationController {

    private final UserReservationService userReservationService;
    private final ReservationOrderPaymentTimeoutService reservationOrderPaymentTimeoutService;

    @ApiOperation("新增预约")
    @ApiOperationSupport(order = 1)
    @PostMapping("/add")
    public R<Integer> add(@RequestBody UserReservationDTO dto) {
        log.info("UserReservationController.add?userId={}, storeId={}", dto.getUserId(), dto.getStoreId());
        try {
            Integer id = userReservationService.add(dto);
            return R.data(id);
        } catch (Exception e) {
            log.error("新增预约失败", e);
            return R.fail(e.getMessage());
        }
    }

    @ApiOperation("修改预约")
    @ApiOperationSupport(order = 2)
    @PostMapping("/update")
    public R<String> update(@RequestBody UserReservationDTO dto) {
        log.info("UserReservationController.update?id={}", dto.getId());
        if (dto.getId() == null) {
            return R.fail("预约ID不能为空");
        }
        try {
            boolean ok = userReservationService.updateReservation(dto);
            return ok ? R.success("修改成功") : R.fail("修改失败");
        } catch (Exception e) {
            log.error("修改预约失败", e);
            return R.fail(e.getMessage());
        }
    }

    @ApiOperation("删除预约")
    @ApiOperationSupport(order = 3)
    @ApiImplicitParam(name = "id", value = "预约ID", dataType = "Integer", paramType = "query", required = true)
    @PostMapping("/delete")
    public R<String> delete(@RequestParam Integer id) {
        log.info("UserReservationController.delete?id={}", id);
        if (id == null) {
            return R.fail("预约ID不能为空");
        }
        try {
            boolean ok = userReservationService.removeReservation(id);
            return ok ? R.success("删除成功") : R.fail("删除失败");
        } catch (Exception e) {
            log.error("删除预约失败", e);
            return R.fail(e.getMessage());
        }
    }

    @ApiOperation("预约详情")
    @ApiOperationSupport(order = 4)
    @ApiImplicitParam(name = "id", value = "预约ID", dataType = "Integer", paramType = "query", required = true)
    @GetMapping("/detail")
    public R<UserReservationVo> detail(@RequestParam Integer id) {
        log.info("UserReservationController.detail?id={}", id);
        if (id == null) {
            return R.fail("预约ID不能为空");
        }
        UserReservationVo vo = userReservationService.getDetail(id);
        if (vo == null) {
            return R.fail("预约不存在");
        }
        return R.data(vo);
    }

    @ApiOperation("分页查询预约列表")
    @ApiOperationSupport(order = 5)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "status", value = "预约状态", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "dateFrom", value = "预约日期起 yyyy-MM-dd", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "dateTo", value = "预约日期止 yyyy-MM-dd", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "pageNum", value = "页码", dataType = "Integer", paramType = "query", defaultValue = "1"),
            @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "Integer", paramType = "query", defaultValue = "10")
    })
    @GetMapping("/page")
    public R<IPage<UserReservationVo>> page(
            @RequestParam(required = false) Integer userId,
            @RequestParam(required = false) Integer storeId,
            @RequestParam(required = false) Integer status,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date dateFrom,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date dateTo,
            @RequestParam(defaultValue = "1") Integer pageNum,
            @RequestParam(defaultValue = "10") Integer pageSize) {
        log.info("UserReservationController.page?userId={}, storeId={}, status={}, pageNum={}, pageSize={}",
                userId, storeId, status, pageNum, pageSize);
        IPage<UserReservationVo> page = userReservationService.pageList(userId, storeId, status, dateFrom, dateTo, pageNum, pageSize);
        return R.data(page);
    }

    @ApiOperation("预约列表（不分页）")
    @ApiOperationSupport(order = 6)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "status", value = "预约状态", dataType = "Integer", paramType = "query")
    })
    @GetMapping("/list")
    public R<List<UserReservationVo>> list(
            @RequestParam(required = false) Integer userId,
            @RequestParam(required = false) Integer storeId,
            @RequestParam(required = false) Integer status) {
        log.info("UserReservationController.list?userId={}, storeId={}, status={}", userId, storeId, status);
        List<UserReservationVo> list = userReservationService.list(userId, storeId, status);
        return R.data(list);
    }

    @ApiOperation("预订信息")
    @ApiOperationSupport(order = 7)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query")
    })
    @GetMapping("/getBookingsByStoreId")
    public R<Map<String, Object>> getBookingsByStoreId(@RequestParam Integer storeId) {
        log.info("UserReservationController.getBookingsByStoreId?storeId={}", storeId);
        Map<String, Object> list = userReservationService.getBookingsByStoreId(storeId);
        return R.data(list);
    }

    /**
     * 获取定桌情况。不传预定日期时：从今天起找首个存在未约满选座的日期并返回该日数据；
     * 传入预定日期时：直接查询该日期的定桌情况（该日预约列表 + 每个选座约满标识 full）。
     */
    @ApiOperation("获取首个未约满日期的预约数据 / 按预定日期查询指定日期的定桌情况")
    @ApiOperationSupport(order = 8)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true),
            @ApiImplicitParam(name = "reservationDate", value = "预定日期，yyyy-MM-dd；不传则从今天起找首个未约满日期", dataType = "String", paramType = "query", required = false)
    })
    @GetMapping("/firstAvailableDay")
    public R<Map<String, Object>> firstAvailableDay(
            @RequestParam Integer storeId,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date reservationDate) {
        log.info("UserReservationController.firstAvailableDay?storeId={}, reservationDate={}", storeId, reservationDate);
        if (storeId == null) {
            return R.fail("门店ID不能为空");
        }
        Map<String, Object> data = userReservationService.findFirstAvailableDayReservations(storeId, reservationDate);
        return R.data(data);
    }

    /**
     * 根据门店ID和多个 user_reservation_table 主键ID，查询该店铺这些桌记录对应的用户预约信息列表。
     */
    @ApiOperation("根据门店与预约桌记录ID列表查询预约详情列表")
    @ApiOperationSupport(order = 9)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true),
            @ApiImplicitParam(name = "userReservationTableId", value = "user_reservation_table 表主键ID（或餐桌ID）", dataType = "Integer", paramType = "query", required = true),
            @ApiImplicitParam(name = "reservationDate", value = "预订日期 yyyy-MM-dd，不传则不按日期过滤", dataType = "String", paramType = "query", required = false)
    })
    @GetMapping("/detailByStoreAndTableRecord")
    public R<List<UserReservationVo>> detailByStoreAndTableRecord(
            @RequestParam Integer storeId,
            @RequestParam Integer userReservationTableId,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date reservationDate) {
        log.info("UserReservationController.detailByStoreAndTableRecord?storeId={}, userReservationTableId={}, reservationDate={}", storeId, userReservationTableId, reservationDate);
        if (storeId == null) {
            return R.fail("门店ID不能为空");
        }
        if (userReservationTableId == null) {
            return R.fail("预约桌记录ID不能为空");
        }
        List<UserReservationVo> list = userReservationService.listDetailByStoreIdAndReservationTableIds(storeId, userReservationTableId, reservationDate);
        return R.data(list);
    }

    /**
     * 为预订订单设置支付超时 Redis 缓存（15 分钟）。
     * 订单创建后调用此接口，超时未支付将自动关闭订单；支付成功后由支付回调自动取消计时。
     */
    @ApiOperation("设置预订订单支付超时（15分钟）")
    @ApiOperationSupport(order = 10)
    @ApiImplicitParam(name = "orderId", value = "预订订单ID（user_reservation_order.id）", dataType = "Integer", paramType = "query", required = true)
    @PostMapping("/setOrderPaymentTimeout")
    public R<String> setOrderPaymentTimeout(@RequestParam Integer orderId) {
        log.info("UserReservationController.setOrderPaymentTimeout?orderId={}", orderId);
        if (orderId == null) {
            return R.fail("订单ID不能为空");
        }
        try {
            userReservationService.setReservationOrderPaymentTimeoutByOrderId(orderId);
            return R.success("已设置支付超时，请在15分钟内完成支付");
        } catch (Exception e) {
            log.error("设置订单支付超时失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 根据订单ID查询详情：门店信息、预订信息、定桌信息
     */
    @ApiOperation("根据订单ID查询详情（门店+预订+定桌，门店信息含 distance、distance2、subwayName、storeLocation）")
    @ApiOperationSupport(order = 11)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderId", value = "预订订单ID（user_reservation_order.id）", dataType = "Integer", paramType = "query", required = true),
            @ApiImplicitParam(name = "jingdu", value = "经度（可选，与 weidu 同时传入时返回用户到门店距离）", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "weidu", value = "纬度（可选）", dataType = "String", paramType = "query")
    })
    @GetMapping("/orderDetail")
    public R<ReservationOrderDetailVo> orderDetail(@RequestParam Integer orderId,
                                                    @RequestParam(required = false) String jingdu,
                                                    @RequestParam(required = false) String weidu) {
        log.info("UserReservationController.orderDetail?orderId={},jingdu={},weidu={}", orderId, jingdu, weidu);
        if (orderId == null) {
            return R.fail("订单ID不能为空");
        }
        ReservationOrderDetailVo vo = userReservationService.getOrderDetailByOrderId(orderId, jingdu, weidu);
        if (vo == null) {
            return R.fail("订单不存在");
        }
        return R.data(vo);
    }
}
