package shop.alien.store.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import shop.alien.entity.result.R;
import shop.alien.entity.store.StoreTable;
import shop.alien.entity.store.dto.CartDTO;
import shop.alien.entity.store.dto.ChangeTableDTO;
import shop.alien.entity.store.vo.*;
import shop.alien.store.feign.DiningServiceFeign;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 点餐服务 Controller
 * 供前端调用 alien-dining 模块的接口
 *
 * @author ssk
 * @version 1.0
 * @date 2025/01/XX
 */
@Slf4j
@Api(tags = {"点餐服务接口"})
@ApiSort(20)
@CrossOrigin
@RestController
@RequestMapping("/dining")
@RequiredArgsConstructor
public class DiningServiceController {

    private final DiningServiceFeign diningServiceFeign;

    /**
     * 从请求头获取 Authorization token
     */
    private String getAuthorization(HttpServletRequest request) {
        String authorization = request.getHeader("Authorization");
        if (authorization == null || authorization.isEmpty()) {
            authorization = request.getHeader("authorization");
        }
        return authorization;
    }

    // ==================== 点餐相关接口 ====================

    @ApiOperation(value = "查询餐桌是否处于就餐中", notes = "免登录可调用，返回 inDining、dinerCount，供前端判断是否跳过选择用餐人数")
    @ApiOperationSupport(order = 0)
    @GetMapping("/table-dining-status")
    public R<TableDiningStatusVO> getTableDiningStatus(
            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
        try {
            log.info("查询餐桌就餐状态: tableId={}", tableId);
            return diningServiceFeign.getTableDiningStatus(tableId);
        } catch (Exception e) {
            log.error("查询餐桌就餐状态失败: {}", e.getMessage(), e);
            return R.fail("查询餐桌就餐状态失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "获取点餐页面信息", notes = "首客选桌时传就餐人数；餐桌已就餐中时可不传就餐人数，将使用已保存人数")
    @ApiOperationSupport(order = 1)
    @GetMapping("/page-info")
    public R<DiningPageInfoVO> getDiningPageInfo(
            HttpServletRequest request,
            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
            @ApiParam(value = "就餐人数（首客必传；餐桌已就餐中时可省略）") @RequestParam(required = false) Integer dinerCount) {
        try {
            String authorization = getAuthorization(request);
            log.info("获取点餐页面信息: tableId={}, dinerCount={}", tableId, dinerCount);
            return diningServiceFeign.getDiningPageInfo(authorization, tableId, dinerCount);
        } catch (Exception e) {
            log.error("获取点餐页面信息失败: {}", e.getMessage(), e);
            return R.fail("获取点餐页面信息失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "搜索菜品", notes = "根据关键词搜索菜品")
    @ApiOperationSupport(order = 2)
    @GetMapping("/search")
    public R<List<CuisineListVO>> searchCuisines(
            HttpServletRequest request,
            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId,
            @ApiParam(value = "搜索关键词", required = true) @RequestParam String keyword,
            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
        try {
            String authorization = getAuthorization(request);
            log.info("搜索菜品: storeId={}, keyword={}, tableId={}", storeId, keyword, tableId);
            return diningServiceFeign.searchCuisines(authorization, storeId, keyword, tableId);
        } catch (Exception e) {
            log.error("搜索菜品失败: {}", e.getMessage(), e);
            return R.fail("搜索菜品失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "根据分类获取菜品列表", notes = "根据分类ID获取菜品列表，支持分页")
    @ApiOperationSupport(order = 3)
    @GetMapping("/cuisines")
    public R<List<CuisineListVO>> getCuisinesByCategory(
            HttpServletRequest request,
            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId,
            @ApiParam(value = "分类ID（可为空，查询所有）") @RequestParam(required = false) Integer categoryId,
            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
            @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Integer page,
            @ApiParam(value = "每页数量", defaultValue = "12") @RequestParam(defaultValue = "12") Integer size) {
        try {
            String authorization = getAuthorization(request);
            log.info("根据分类获取菜品列表: storeId={}, categoryId={}, tableId={}, page={}, size={}",
                    storeId, categoryId, tableId, page, size);
            return diningServiceFeign.getCuisinesByCategory(authorization, storeId, categoryId, tableId, page, size);
        } catch (Exception e) {
            log.error("根据分类获取菜品列表失败: {}", e.getMessage(), e);
            return R.fail("根据分类获取菜品列表失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "获取菜品详情", notes = "获取菜品详细信息，包含图片列表、月售数量等")
    @ApiOperationSupport(order = 4)
    @GetMapping("/cuisine/{cuisineId}")
    public R<CuisineDetailVO> getCuisineDetail(
            HttpServletRequest request,
            @ApiParam(value = "菜品ID", required = true) @PathVariable Integer cuisineId,
            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
        try {
            String authorization = getAuthorization(request);
            log.info("获取菜品详情: cuisineId={}, tableId={}", cuisineId, tableId);
            return diningServiceFeign.getCuisineDetail(authorization, cuisineId, tableId);
        } catch (Exception e) {
            log.error("获取菜品详情失败: {}", e.getMessage(), e);
            return R.fail("获取菜品详情失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "获取可领取的优惠券列表", notes = "获取用户可领取的优惠券")
    @ApiOperationSupport(order = 5)
    @GetMapping("/coupons/available")
    public R<List<AvailableCouponVO>> getAvailableCoupons(
            HttpServletRequest request,
            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId) {
        try {
            String authorization = getAuthorization(request);
            log.info("获取可领取的优惠券列表: storeId={}", storeId);
            return diningServiceFeign.getAvailableCoupons(authorization, storeId);
        } catch (Exception e) {
            log.error("获取可领取的优惠券列表失败: {}", e.getMessage(), e);
            return R.fail("获取可领取的优惠券列表失败: " + e.getMessage());
        }
    }

    // ==================== 订单相关接口 ====================

    @ApiOperation(value = "获取购物车", notes = "根据桌号ID获取购物车信息")
    @ApiOperationSupport(order = 6)
    @GetMapping("/order/cart/{tableId}")
    public R<CartDTO> getCart(
            HttpServletRequest request,
            @ApiParam(value = "桌号ID", required = true) @PathVariable Integer tableId) {
        try {
            String authorization = getAuthorization(request);
            log.info("获取购物车: tableId={}", tableId);
            return diningServiceFeign.getCart(authorization, tableId);
        } catch (Exception e) {
            log.error("获取购物车失败: {}", e.getMessage(), e);
            return R.fail("获取购物车失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "换桌", notes = "按桌号换桌，迁移购物车、未完成订单及关联数据。支持点餐未下单场景，只需传原桌号与目标桌号，无需订单号。")
    @ApiOperationSupport(order = 7)
    @PostMapping("/order/change-table")
    public R<CartDTO> changeTable(
            HttpServletRequest request,
            @ApiParam(value = "换桌参数（原桌号ID、目标桌号ID、换桌原因）", required = true) @RequestBody ChangeTableDTO dto) {
        try {
            String authorization = getAuthorization(request);
            log.info("换桌: fromTableId={}, toTableId={}, changeReason={}", dto.getFromTableId(), dto.getToTableId(), dto.getChangeReason());
            return diningServiceFeign.changeTable(authorization, dto);
        } catch (Exception e) {
            log.error("换桌失败: {}", e.getMessage(), e);
            return R.fail("换桌失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "获取订单详情", notes = "根据订单ID获取订单详细信息")
    @ApiOperationSupport(order = 8)
    @GetMapping("/order/{orderId}")
    public R<OrderDetailWithChangeLogVO> getOrderDetail(
            HttpServletRequest request,
            @ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
        try {
            String authorization = getAuthorization(request);
            log.info("获取订单详情: orderId={}", orderId);
            return diningServiceFeign.getOrderDetail(authorization, orderId);
        } catch (Exception e) {
            log.error("获取订单详情失败: {}", e.getMessage(), e);
            return R.fail("获取订单详情失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "获取订单列表", notes = "分页获取订单列表，支持按状态筛选")
    @ApiOperationSupport(order = 8)
    @GetMapping("/order/list")
    public R<IPage<StoreOrderPageVO>> getOrderList(
            HttpServletRequest request,
            @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Integer page,
            @ApiParam(value = "每页数量", defaultValue = "10") @RequestParam(defaultValue = "10") Integer size,
            @ApiParam(value = "订单状态（可选）") @RequestParam(required = false) Integer status) {
        try {
            String authorization = getAuthorization(request);
            log.info("获取订单列表: page={}, size={}, status={}", page, size, status);
            return diningServiceFeign.getOrderList(authorization, page, size, status);
        } catch (Exception e) {
            log.error("获取订单列表失败: {}", e.getMessage(), e);
            return R.fail("获取订单列表失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "分页查询订单列表", notes = "分页查询订单列表，包含订单中的菜品数量、菜品名称、菜品图片。支持按订单编号或菜品名称搜索（限15字）")
    @ApiOperationSupport(order = 8)
    @GetMapping("/order/page")
    public R<IPage<StoreOrderPageVO>> getOrderPage(
            HttpServletRequest request,
            @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Long current,
            @ApiParam(value = "每页数量", defaultValue = "10") @RequestParam(defaultValue = "10") Long size,
            @ApiParam(value = "门店ID") @RequestParam(required = false) Integer storeId,
            @ApiParam(value = "桌号ID") @RequestParam(required = false) Integer tableId,
            @ApiParam(value = "订单状态（0:待支付, 1:已支付, 2:已取消, 3:已完成）") @RequestParam(required = false) Integer orderStatus,
            @ApiParam(value = "搜索关键词（订单编号或菜品名称，限15字）") @RequestParam(required = false) String keyword) {
        try {
            String authorization = getAuthorization(request);
            log.info("分页查询订单列表: current={}, size={}, storeId={}, tableId={}, orderStatus={}, keyword={}",
                    current, size, storeId, tableId, orderStatus, keyword);
            R<Page<StoreOrderPageVO>> result = diningServiceFeign.getOrderPage(authorization, current, size, storeId, tableId, orderStatus, keyword);
            // 将 Page 转换为 IPage 返回（Page 实现了 IPage 接口，可以直接返回）
            return R.data(result.getData());
        } catch (Exception e) {
            log.error("分页查询订单列表失败: {}", e.getMessage(), e);
            return R.fail("分页查询订单列表失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "查询订单变更记录", notes = "根据订单ID查询订单的所有变更记录（按批次分组），用于展示每次下单/加餐都加了什么商品")
    @ApiOperationSupport(order = 9)
    @GetMapping("/order/change-log/{orderId}")
    public R<List<OrderChangeLogBatchVO>> getOrderChangeLogs(
            HttpServletRequest request,
            @ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
        try {
            String authorization = getAuthorization(request);
            log.info("查询订单变更记录: orderId={}", orderId);
            return diningServiceFeign.getOrderChangeLogs(authorization, orderId);
        } catch (Exception e) {
            log.error("查询订单变更记录失败: {}", e.getMessage(), e);
            return R.fail("查询订单变更记录失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "商家手动完成订单", notes = "供商家使用，手动点击完成订单。不校验订单是否处于已支付状态，直接将订单状态改为已完成。订单状态：0-待支付，1-已支付，2-已取消，3-已完成")
    @ApiOperationSupport(order = 10)
    @PostMapping("/order/complete-by-merchant/{orderId}")
    public R<Boolean> completeOrderByMerchant(
            HttpServletRequest request,
            @ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
        try {
            String authorization = getAuthorization(request);
            log.info("商家手动完成订单: orderId={}", orderId);
            return diningServiceFeign.completeOrderByMerchant(authorization, orderId);
        } catch (Exception e) {
            log.error("商家手动完成订单失败: {}", e.getMessage(), e);
            return R.fail("商家手动完成订单失败: " + e.getMessage());
        }
    }

    // ==================== 用户相关接口 ====================

    @ApiOperation(value = "获取用户信息", notes = "获取当前登录用户的详细信息（从token中获取用户ID）")
    @ApiOperationSupport(order = 9)
    @GetMapping("/user/info")
    public R<Object> getUserInfo(HttpServletRequest request) {
        try {
            String authorization = getAuthorization(request);
            log.info("获取用户信息");
            return diningServiceFeign.getUserInfo(authorization);
        } catch (Exception e) {
            log.error("获取用户信息失败: {}", e.getMessage(), e);
            return R.fail("获取用户信息失败: " + e.getMessage());
        }
    }

    // ==================== 门店信息接口 ====================

    @ApiOperation(value = "根据门店ID查询桌号列表", notes = "查询指定门店下的所有桌号")
    @ApiOperationSupport(order = 10)
    @GetMapping("/store/tables")
    public R<List<StoreTable>> getTablesByStoreId(
            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId) {
        try {
            log.info("根据门店ID查询桌号列表: storeId={}", storeId);
            return diningServiceFeign.getTablesByStoreId(storeId);
        } catch (Exception e) {
            log.error("根据门店ID查询桌号列表失败: {}", e.getMessage(), e);
            return R.fail("根据门店ID查询桌号列表失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "根据门店ID查询菜品种类及各类别下菜品", notes = "一次返回所有菜品种类及每个分类下的菜品列表；可选 keyword 按菜品名称模糊查询")
    @ApiOperationSupport(order = 11)
    @GetMapping("/store/info/categories-with-cuisines")
    public R<List<CategoryWithCuisinesVO>> getCategoriesWithCuisinesByStoreId(
            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId,
            @ApiParam(value = "菜品名称模糊查询关键词（可选）") @RequestParam(required = false) String keyword) {
        try {
            log.info("根据门店ID查询菜品种类及菜品: storeId={}, keyword={}", storeId, keyword);
            return diningServiceFeign.getCategoriesWithCuisinesByStoreId(storeId, keyword);
        } catch (Exception e) {
            log.error("查询菜品种类及菜品失败: {}", e.getMessage(), e);
            return R.fail("查询菜品种类及菜品失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "删除菜品种类", notes = "仅删除绑定关系和菜品种类（逻辑删除）；价目表菜品不变")
    @ApiOperationSupport(order = 12)
    @DeleteMapping("/store/info/category/{categoryId}")
    public R<Boolean> deleteCategory(
            @ApiParam(value = "菜品种类ID", required = true) @PathVariable Integer categoryId) {
        try {
            log.info("删除菜品种类: categoryId={}", categoryId);
            return diningServiceFeign.deleteCategory(categoryId);
        } catch (Exception e) {
            log.error("删除菜品种类失败: {}", e.getMessage(), e);
            return R.fail("删除菜品种类失败: " + e.getMessage());
        }
    }

    // ==================== 文件上传接口 ====================

    @ApiOperation(value = "上传图片到OSS", notes = "支持图片、视频或PDF文件上传，返回OSS文件路径")
    @ApiOperationSupport(order = 11)
    @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public R<String> uploadFile(
            @ApiParam(value = "文件对象", required = true) @RequestParam("file") MultipartFile file) {
        try {
            if (file == null || file.isEmpty()) {
                return R.fail("文件不能为空");
            }
            log.info("上传文件: fileName={}, size={}", file.getOriginalFilename(), file.getSize());
            return diningServiceFeign.uploadFile(file);
        } catch (Exception e) {
            log.error("上传文件失败: {}", e.getMessage(), e);
            return R.fail("上传文件失败: " + e.getMessage());
        }
    }
}
