package shop.alien.store.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import shop.alien.entity.store.UserReservation;
import shop.alien.entity.store.dto.UserReservationDTO;
import shop.alien.entity.store.vo.UserReservationVo;
import shop.alien.store.vo.ReservationOrderDetailVo;

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

/**
 * 用户预约 服务类
 *
 * @author system
 */
public interface UserReservationService extends IService<UserReservation> {

    /**
     * 新增预约（含关联桌号）
     *
     * @param dto 预约DTO
     * @return 预约ID
     */
    Integer add(UserReservationDTO dto);

    /**
     * 修改预约（含关联桌号）
     *
     * @param dto 预约DTO
     * @return 是否成功
     */
    boolean updateReservation(UserReservationDTO dto);

    /**
     * 删除预约（假删除：将 user_reservation_order、user_reservation_table、user_reservation 的 delete_flag 置为 1，与 add 新建表数据对应）
     *
     * @param id 预约ID
     * @return 是否成功
     */
    boolean removeReservation(Integer id);

    /**
     * 预定订单删除：按订单ID逻辑删除订单及预定信息（user_reservation_order、user_reservation_table、user_reservation 的 delete_flag 置为 1）
     *
     * @param orderId 预订订单ID（user_reservation_order.id）
     * @return 是否成功
     */
    boolean deleteOrderAndReservationByOrderId(Integer orderId);

    /**
     * 查询预约详情（含关联桌号ID列表）
     *
     * @param id 预约ID
     * @return 预约VO，不存在返回 null
     */
    UserReservationVo getDetail(Integer id);

    /**
     * 分页查询预约列表
     *
     * @param userId   用户ID（可选）
     * @param storeId  门店ID（可选）
     * @param status   预约状态（可选）
     * @param dateFrom 预约日期起（可选）
     * @param dateTo   预约日期止（可选）
     * @param pageNum  页码
     * @param pageSize 每页条数
     * @return 分页结果
     */
    IPage<UserReservationVo> pageList(Integer userId, Integer storeId, Integer status,
                                      Date dateFrom, Date dateTo,
                                      Integer pageNum, Integer pageSize);

    /**
     * 列表查询预约（不分页）
     *
     * @param userId  用户ID（可选）
     * @param storeId 门店ID（可选）
     * @param status  预约状态（可选）
     * @return 预约VO列表
     */
    List<UserReservationVo> list(Integer userId, Integer storeId, Integer status);

    Map<String, Object> getBookingsByStoreId(Integer storeId);

    /**
     * 从今天起查找第一个存在未约满选座的日期，并返回该日的预约数据及每个选座的约满标识。
     * 不按商户设定计算，仅根据 UserReservation、UserReservationTable 数据：以日期为集合，每个选座（桌）当日若被任意有效预约占用则为已约满，否则未约满；同一标识字段 full（true=已约满，false=未约满）。
     *
     * @param storeId 门店ID
     * @return Map：date、reservations、tableStatusList（每项含 tableId/tableNumber/seatingCapacity/full）
     */
    Map<String, Object> findFirstAvailableDayReservations(Integer storeId);

    /**
     * 查询商家端预约信息列表
     *
     * @param storeId    门店ID（必填）
     * @param status     预约状态（可选，0:待确认 1:已确认 2:已到店 3:已取消 4:未到店超时）
     * @param dateFrom   预约日期起（可选）
     * @param dateTo     预约日期止（可选）
     * @param orderStatus 订单状态（可选，0:待支付 1:待使用 2:已完成 3:已过期 4:已取消 5:已关闭 6:退款中 7:已退款 8:商家预订）
     * @return 预约信息列表
     */
    java.util.List<shop.alien.entity.store.vo.StoreReservationListVo> getStoreReservationList(
            Integer storeId, Integer status, java.util.Date dateFrom, java.util.Date dateTo, Integer orderStatus);

    /**
     * 商家端取消预约
     *
     * @param reservationId 预约ID
     * @return 是否成功
     */
    boolean cancelReservationByStore(Integer reservationId);

    /**
     * 商家端删除预订信息
     * 只有订单状态为已取消(4)、已退款(7)、已完成(2)时才能删除
     *
     * @param reservationId 预约ID
     * @return 是否成功
     */
    boolean deleteReservationByStore(Integer reservationId);

    /**
     * 商家端加时
     * 更新预订信息的结束时间，新的结束时间 = 加时开始时间 + 加时分钟数
     *
     * @param reservationId 预约ID
     * @param addTimeStart 加时开始时间（HH:mm格式）
     * @param addTimeMinutes 加时分钟数
     * @return 是否成功
     */
    boolean addTimeByStore(Integer reservationId, String addTimeStart, Integer addTimeMinutes);

    /**
     * 按预定日期查询指定日期的定桌情况（该日预约列表 + 每个选座的约满标识 full）。
     * 传参 reservationDate 不为空时使用；与 findFirstAvailableDayReservations(storeId) 同结构。
     *
     * @param storeId         门店ID
     * @param reservationDate 预定日期，格式 yyyy-MM-dd
     * @return Map：date、reservations、tableStatusList
     */
    Map<String, Object> findFirstAvailableDayReservations(Integer storeId, Date reservationDate);

    /**
     * 根据门店ID和 user_reservation_table 主键ID，查询该店铺该桌对应的用户预约详情。
     *
     * @param storeId              门店ID
     * @param userReservationTableId user_reservation_table 表主键 id
     * @return 预约详情 VO，不存在或门店不匹配返回 null
     */
    UserReservationVo getDetailByStoreIdAndReservationTableId(Integer storeId, Integer userReservationTableId);

    /**
     * 根据门店ID和 user_reservation_table 主键ID（或餐桌ID），查询该店铺这些桌记录对应的用户预约详情列表；可选按预订日期过滤。
     *
     * @param storeId               门店ID
     * @param userReservationTableId user_reservation_table 表主键或餐桌 id
     * @param reservationDate       预订日期，为 null 时不按日期过滤
     * @return 预约详情 VO 列表（仅包含存在且属于该门店的预约，去重）
     */
    List<UserReservationVo> listDetailByStoreIdAndReservationTableIds(Integer storeId, Integer userReservationTableId, Date reservationDate);

    /**
     * 为预订订单设置支付超时 Redis 缓存（15 分钟），超时未支付将自动关闭订单。
     * 订单创建后调用；支付成功后由支付回调取消计时。
     *
     * @param orderId 预订订单ID user_reservation_order.id
     */
    void setReservationOrderPaymentTimeoutByOrderId(Integer orderId);

    /**
     * 根据订单ID查询详情：门店信息（含 distance、distance2、subwayName、storeLocation）、预订信息、定桌信息。
     *
     * @param orderId 预订订单ID user_reservation_order.id
     * @param jingdu  经度（可选，与 weidu 同时传入时返回用户到门店距离 distance）
     * @param weidu   纬度（可选）
     * @return 详情 VO，订单不存在返回 null
     */
    ReservationOrderDetailVo getOrderDetailByOrderId(Integer orderId, String jingdu, String weidu);

    /**
     * 定时任务：将超过未到店截止时间且「订单状态为待使用」的预订标记为已过期/未到店超时。
     * retain_position_flag=1：截止 = start_time + retention_duration；否则仅按 start_time 判断超时。
     * 更新：user_reservation.status = 4(未到店超时)，user_reservation_order.order_status = 3(已过期)。
     *
     * @return 本次更新的预约数量（即更新的 order 数量）
     */
    int markReservationTimeoutByEndTime();

    /**
     * 定时任务：订单状态为待使用且当前时间距离预定开始时间小于等于30分钟时，发送到店提醒短信。
     * 短信名称：到店提醒。内容：您在14:00预订了xxx(店铺名称)A01(桌号或名称)的桌位,请您及时到店
     *
     * @return 本次发送短信条数
     */
    int sendArrivalReminderSms();

    /**
     * 为单个订单发送到店提醒短信（供定时任务或 Redis 过期回调调用，不校验 Redis 防重）
     *
     * @param orderId 订单ID
     * @return true 发送成功，false 未发送或发送失败
     */
    boolean sendArrivalReminderSmsForOrder(Integer orderId);
}
