package com.red.circle.wallet.adapter.app;

import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.common.business.dto.cmd.app.AppAccountCmd;
import com.red.circle.common.business.dto.cmd.app.AppFlowCmd;
import com.red.circle.common.business.dto.cmd.app.AppUserIdCmd;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.web.controller.BaseController;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.wallet.app.dto.clientobject.FreightAccountCO;
import com.red.circle.wallet.app.dto.clientobject.FreightDealerUserSearchResultCO;
import com.red.circle.wallet.app.dto.clientobject.FreightRunningWaterCO;
import com.red.circle.wallet.app.dto.clientobject.FreightSearchUserResultCO;
import com.red.circle.wallet.app.dto.clientobject.FreightSellerCO;
import com.red.circle.wallet.app.dto.cmd.*;
import com.red.circle.wallet.app.service.UserFreightService;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.List;

import com.red.circle.wallet.infra.database.rds.entity.freight.FreightBalance;
import com.red.circle.wallet.infra.database.rds.service.freight.FreightBalanceService;
import com.red.circle.wallet.inner.error.FreightErrorCode;
import com.red.circle.wallet.inner.error.WalletErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

/**
 * <p>
 * 经销商货运代理 前端控制器.
 * </p>
 *
 * @author zongpubin on 2023-07-14 15:28
 * @eo.api-type http
 * @eo.groupName 钱包服务.货运管理
 * @eo.path /wallet/freight
 */
@RestController
@RequestMapping("/freight")
@RequiredArgsConstructor
public class FreightRestController extends BaseController {

  private final UserFreightService userFreightService;
  private final FreightBalanceService freightBalanceService;
  private final RedisTemplate<String, String> redisTemplate;

  /**
   * 货运账户余额.
   *
   * @eo.name 货运账户余额.
   * @eo.url /balance
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/balance")
  public BigDecimal getFreightAvailableBalance(AppExtCommand cmd) {
    return userFreightService.getFreightAvailableBalance(cmd);
  }

  /**
   * 获取货运流水.
   *
   * @eo.name 获取货运流水.
   * @eo.url /assets/running-water
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping(value = "/assets/running-water")
  public List<FreightRunningWaterCO> flowFreightAssetsRunningWater(AppFlowCmd cmd) {
    return userFreightService.flowFreightAssetsRunningWater(cmd);
  }

  /**
   * 获取指定卖家货运流水.
   *
   * @eo.name 获取指定卖家货运流水.
   * @eo.url /seller/assets/running-water
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping(value = "/seller/assets/running-water")
  public List<FreightRunningWaterCO> flowFreightSellerRunningWater(
      FreightSellerRunningWaterQryCmd cmd) {
    return userFreightService.flowFreightSellerRunningWater(cmd);
  }

  /**
   * 搜索货运代理用户.
   *
   * @eo.name 搜索货运代理用户.
   * @eo.url /search-user
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/search-user")
  public FreightSearchUserResultCO searchFreightUser(AppAccountCmd cmd) {
    return userFreightService.searchFreightUser(cmd);
  }

  /**
   * 是否是货运代理账号.
   *
   * @eo.name 是否是货运代理账号.
   * @eo.url /check
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/check")
  public Boolean checkFreight(AppExtCommand cmd) {
    return userFreightService.checkFreight(cmd);
  }

  /**
   * 货运代理给用户发货.
   *
   * @eo.name 货运代理给用户发货.
   * @eo.url /ship
   * @eo.method post
   * @eo.request-type json
   */
  @PostMapping("/ship")
  public BigDecimal sendFreightShip(@RequestBody @Validated FreightShipSendCmd cmd) {
    return userFreightService.sendFreightShip(cmd);
  }

  @PostMapping("/threshold")
  public Boolean updateFreightBalance(@RequestBody @Validated FreightBalanceUpdateCmd cmd) {
      // 校验日期是否为每月一号
      LocalDate today = LocalDate.now();
      if (today.getDayOfMonth() != 1 && today.getMonthValue() != 12) {
          throw new RuntimeException("This operation is only allowed on the 1st of each month");
      }

      String monthKey = "freight:threshold:" + cmd.getReqUserId() + ":" + today.format(DateTimeFormatter.ofPattern("yyyy-MM"));
      LocalDate lastDay = today.with(TemporalAdjusters.lastDayOfMonth());
      LocalDateTime endOfMonth = lastDay.atTime(23, 59, 59);
      long ttl = Duration.between(LocalDateTime.now(), endOfMonth).getSeconds();
      if (ttl < 1) {
          ttl = 1;
      }

      // 使用 Redis SETNX 实现“当月仅执行一次”
      Boolean firstDo = redisTemplate.opsForValue().setIfAbsent(
              monthKey,
              "done",
              Duration.ofSeconds(ttl)
      );

      if (Boolean.FALSE.equals(firstDo)) {
          throw new RuntimeException("This operation has been performed this month and cannot be repeated");
      }

      FreightBalance freightBalance = freightBalanceService.getFreightBalance(cmd.getReqUserId());
      ResponseAssert.notNull(FreightErrorCode.NOT_FREIGHT, freightBalance);
      freightBalance.setDeliveryThreshold(cmd.getDeliveryThreshold());
      return freightBalanceService.updateSelectiveById(freightBalance);
  }

    /**
     * 查询货运代理信息
     * @param cmd
     * @return
     */
  @GetMapping("/threshold")
  public FreightBalance getFreightThreshold(AppAccountCmd cmd) {
      FreightBalance freightBalance = freightBalanceService.getFreightBalance(cmd.getReqUserId());
      if (freightBalance != null) {
          String monthKey = "freight:threshold:" + cmd.getReqUserId() + ":" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
          freightBalance.setSettinged(redisTemplate.opsForValue().get(monthKey) != null);
      }
      return freightBalance;
  }

  /**
   * 货运代理是否首次充值.
   *
   * @eo.name 货运代理是否首次充值.
   * @eo.url /first-recharge
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/first-recharge")
  public Boolean checkFreightFirstRecharge(@Validated AppUserIdCmd cmd) {
    return userFreightService.checkFreightFirstRecharge(cmd);
  }

  /**
   * 经销商搜索货运用户.
   *
   * @eo.name 经销商搜索货运用户.
   * @eo.url /dealer/search-user
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/dealer/search-user")
  public FreightDealerUserSearchResultCO searchDealerFreightResult(@Validated AppAccountCmd cmd) {
    return userFreightService.searchDealerFreightResult(cmd);
  }

  /**
   * 经销商发货给货运代理.
   *
   * @eo.name 经销商发货给货运代理.
   * @eo.url /dealer/ship/freight
   * @eo.method post
   * @eo.request-type json
   */
  @PostMapping("/dealer/ship/freight")
  public BigDecimal dealerToFreightShip(@RequestBody @Validated FreightDealerShipCmd cmd) {
    return userFreightService.dealerToFreightShip(cmd);
  }

  /**
   * 经销商卖家给用户发货.
   *
   * @eo.name 经销商卖家给用户发货.
   * @eo.url /dealer/ship
   * @eo.method post
   * @eo.request-type json
   */
  @PostMapping("/dealer/ship")
  public BigDecimal dealerToUserShip(@RequestBody @Validated FreightDealerToUserShipCmd cmd) {
    return userFreightService.dealerToUserShip(cmd);
  }

  /**
   * 是否是经销商
   *
   * @eo.name 是否是经销商
   * @eo.url /seller/check/dealer
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/seller/check/dealer")
  public Boolean checkDealer(AppExtCommand cmd) {
    return userFreightService.checkDealer(cmd);
  }

  /**
   * 经销商添加卖家.
   *
   * @eo.name 经销商添加卖家.
   * @eo.url /seller/add
   * @eo.method post
   * @eo.request-type json
   */
  @PostMapping("/seller/add")
  public void addFreightSeller(@RequestBody @Validated FreightSellerCmd cmd) {
    userFreightService.addFreightSeller(cmd);
  }

  /**
   * 经销商卖家列表
   *
   * @eo.name 经销商卖家列表
   * @eo.url /seller/list
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/seller/list")
  public List<FreightSellerCO> listFreightSeller(AppExtCommand cmd) {
    return userFreightService.listFreightSeller(cmd);
  }

  /**
   * 是否是经销商卖家.
   *
   * @eo.name 是否是经销商卖家.
   * @eo.url /seller/check
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/seller/check")
  public Boolean checkSeller(AppExtCommand cmd) {
    return userFreightService.checkSeller(cmd);
  }

  /**
   * 获取货运代理相关信息.
   *
   * @eo.name 获取货运代理相关信息.
   * @eo.url /seller/freight-info
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/seller/freight-info")
  public FreightAccountCO getFreightAccountInfo(AppExtCommand cmd) {
    return userFreightService.getFreightAccountInfo(cmd);
  }

  /**
   * 获取商家信息.
   *
   * @eo.name 获取商家信息.
   * @eo.url /seller/search
   * @eo.method get
   * @eo.request-type formdata
   */
  @GetMapping("/seller/search")
  public FreightSellerCO searchSellerById(FreightSellerQryCmd cmd) {
    return userFreightService.searchSellerById(cmd);
  }

  /**
   * 经销商添卖家授权额度修改.
   *
   * @eo.name 经销商添卖家授权额度修改.
   * @eo.url /seller/update-usable-gold
   * @eo.method post
   * @eo.request-type json
   */
  @PostMapping("/seller/update-usable-gold")
  public void updateUsableGold(@RequestBody @Validated FreightSellerUsableGoldCmd cmd) {
    userFreightService.updateUsableGold(cmd);
  }


}
