import { DataModel, transformArrayDataModel, transformDataModel, type KeyValue, type NewDataModel } from '@imengyu/js-request-transform';
import { AppServerRequestModule } from '../RequestModules';
import { transformSomeToArray } from '../Utils';
import type { RequestApiResult } from '@imengyu/imengyu-utils';

/** 流水/日志通用字段 */
abstract class GrowthLogBase extends DataModel<GrowthLogBase> {
  id!: number;
  villageId = null as number | null;
  userId = null as number | null;
  sourceTable = '';
  sourceId = null as number | null;
  remark = '';
  createtime = '' as string | null;
  updatetime = '' as string | null;
  deletetime = '' as string | null;
  villageName = '';
  nickname = '';
  username = '';
  volunteerName = '';
}

export class GrowthTaskLogItem extends GrowthLogBase {
  constructor() {
    super(GrowthTaskLogItem, '任务日志');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      rewardWater: { clientSide: 'number', serverSide: 'number' },
      rewardLight: { clientSide: 'number', serverSide: 'number' },
      rewardFruit: { clientSide: 'number', serverSide: 'number' },
    };
  }

  taskKey = '';
  taskName = '';
  rewardWater = 0;
  rewardLight = 0;
  rewardFruit = 0;
}

export class GrowthFruitLogItem extends GrowthLogBase {
  constructor() {
    super(GrowthFruitLogItem, '乡源果流水');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      fruit: { clientSide: 'number', serverSide: 'number' },
      beforeFruit: { clientSide: 'number', serverSide: 'number' },
      afterFruit: { clientSide: 'number', serverSide: 'number' },
    };
  }

  type = '' as 'pick' | 'task' | 'bless' | 'exchange' | string;
  typeText = '';
  fruit = 0;
  beforeFruit = 0;
  afterFruit = 0;
}

export class GrowthLightLogItem extends GrowthLogBase {
  constructor() {
    super(GrowthLightLogItem, '乡源光流水');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      light: { clientSide: 'number', serverSide: 'number' },
      beforeLight: { clientSide: 'number', serverSide: 'number' },
      afterLight: { clientSide: 'number', serverSide: 'number' },
    };
  }

  type = '' as 'water' | 'fertilize' | 'task' | 'bless' | string;
  typeText = '';
  light = 0;
  beforeLight = 0;
  afterLight = 0;
}

export class BlessPackageItem extends DataModel<BlessPackageItem> {
  constructor() {
    super(BlessPackageItem, '赐福套餐');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      amount: { clientSide: 'number', serverSide: 'number' },
      addLight: { clientSide: 'number', serverSide: 'number' },
      addFruit: { clientSide: 'number', serverSide: 'number' },
      multiple: { clientSide: 'number', serverSide: 'number' },
      days: { clientSide: 'number', serverSide: 'number' },
      status: { clientSide: 'number', serverSide: 'number' },
    };
  }

  id!: number;
  name = '';
  amount = 0;
  image = '';
  addLight = 0;
  addFruit = 0;
  multiple = 0;
  days = 0;
  status = 0;
  statusText = '';
  createtime = '' as string | null;
  updatetime = '' as string | null;
  deletetime = '' as string | null;
}

export class BlessOrderItem extends DataModel<BlessOrderItem> {
  constructor() {
    super(BlessOrderItem, '赐福订单');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      villageId: { clientSide: 'number', serverSide: 'number' },
      userId: { clientSide: 'number', serverSide: 'number' },
      blessId: { clientSide: 'number', serverSide: 'number' },
      amount: { clientSide: 'number', serverSide: 'number' },
      addLight: { clientSide: 'number', serverSide: 'number' },
      addFruit: { clientSide: 'number', serverSide: 'number' },
      multiple: { clientSide: 'number', serverSide: 'number' },
      status: { clientSide: 'number', serverSide: 'number' },
    };
    this._convertKeyType = (key) => {
      if (key.endsWith('Text')) return undefined;
      if (key === 'startTime' || key === 'endTime' || key === 'payTime') {
        return { clientSide: 'date', serverSide: 'number' };
      }
      return undefined;
    };
  }

  id!: number;
  villageId = null as number | null;
  userId = null as number | null;
  blessId = null as number | null;
  amount = 0;
  addLight = 0;
  addFruit = 0;
  multiple = 0;
  startTime = null as Date | null;
  endTime = null as Date | null;
  status = 0;
  remark = '' as string | null;
  payTime = null as Date | null;
  createtime = '' as string | null;
  updatetime = '' as string | null;
  deletetime = '' as string | null;
  villageName = '';
  nickname = '';
  username = '';
  volunteerName = '';
  blessName = '';
  startTimeText = '';
  endTimeText = '';
  statusText = '';
  payTimeText = '';
}
export class BlessOrderConfirm extends DataModel<BlessOrderConfirm> {
  constructor() {
    super(BlessOrderConfirm, '赐福订单确认');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      order: { 
        clientSide: 'object', 
        clientSideChildDataModel: BlessOrderItem, 
        serverSide: 'undefined', 
        clientSideRequired: true 
      },
      pay: { 
        clientSide: 'object',
        clientSideChildDataModel: {
          convertTable: {
            appId: { clientSide: 'string', clientSideRequired: true },
            timeStamp: { clientSide: 'string', clientSideRequired: true },
            nonceStr: { clientSide: 'string', clientSideRequired: true },
            package: { clientSide: 'string', clientSideRequired: true },
            signType: { clientSide: 'string', clientSideRequired: true },
            paySign: { clientSide: 'string', clientSideRequired: true },
          }
        },
        serverSide: 'undefined',
        clientSideRequired: true,
      },
    };
  }

  order !: BlessOrderItem;
  pay !: {
    appId: string;
    timeStamp: string;
    nonceStr: string;
    package: string;
    signType: string;
    paySign: string;
  };
}

export class UpgradePackageItem extends DataModel<UpgradePackageItem> {
  constructor() {
    super(UpgradePackageItem, '升级套餐');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      vipLevel: { clientSide: 'number', serverSide: 'number' },
      price: { clientSide: 'number', serverSide: 'number' },
      imageLimit: { clientSide: 'number', serverSide: 'number' },
      storageLimit: { clientSide: 'number', serverSide: 'number' },
      managerLimit: { clientSide: 'number', serverSide: 'number' },
      isRecommend: { clientSide: 'boolean', serverSide: 'number' },
      sort: { clientSide: 'number', serverSide: 'number' },
      status: { clientSide: 'number', serverSide: 'number' },
    };
  }

  id!: number;
  name = '';
  vipLevel = 0;
  price = 0;
  imageLimit = 0;
  storageLimit = 0;
  managerLimit = 0;
  isRecommend = false;
  isRecommendText = '';
  desc = '';
  content = '';
  sort = 0;
  status = 0;
  statusText = '';
  createtime = '' as string | null;
  updatetime = '' as string | null;
  deletetime = '' as string | null;
}

export class DropFruitResult extends DataModel<DropFruitResult> {
  constructor() {
    super(DropFruitResult, '产果结果');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      fruitRemain: { clientSide: 'number', serverSide: 'number' },
    };
  }

  fruitRemain = 0;
}

export class UpgradeOrderItem extends DataModel<UpgradeOrderItem> {
  constructor() {
    super(UpgradeOrderItem, '升级订单');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      villageId: { clientSide: 'number', serverSide: 'number' },
      upgradeLevelId: { clientSide: 'number', serverSide: 'number' },
      vipLevel: { clientSide: 'number', serverSide: 'number' },
      userId: { clientSide: 'number', serverSide: 'number' },
      price: { clientSide: 'number', serverSide: 'number' },
      imageLimit: { clientSide: 'number', serverSide: 'number' },
      storageLimit: { clientSide: 'number', serverSide: 'number' },
      managerLimit: { clientSide: 'number', serverSide: 'number' },
      money: { clientSide: 'number', serverSide: 'number' },
      payType: { clientSide: 'number', serverSide: 'number' },
      status: { clientSide: 'number', serverSide: 'number' },
      volunteerId: { clientSide: 'number', serverSide: 'number' },
    };
    this._convertKeyType = (key) => {
      if (key.endsWith('Text')) return undefined;
      if (key === 'payTime') {
        return { clientSide: 'date', serverSide: 'number' };
      }
      return undefined;
    };
  }

  id!: number;
  orderNo = '';
  villageId = null as number | null;
  upgradeLevelId = null as number | null;
  vipLevel = 0;
  userId = null as number | null;
  levelName = '';
  price = 0;
  imageLimit = 0;
  storageLimit = 0;
  managerLimit = 0;
  money = 0;
  /** 支付方式: 1=线上支付, 2=对公付款 */
  payType = 0;
  payVoucher = '';
  /** 状态: -1=已取消, 0=未支付, 1=已支付, 2=待审核（对公付款审核凭证） */
  status = 0;
  payTime = null as Date | null;
  villageName = '';
  volunteerName = '';
  volunteerId = null as number | null;
  statusText = '';
  payTimeText = '';
  createtime = '' as string | null;
  updatetime = '' as string | null;
  deletetime = '' as string | null;
}

export class UpgradeOrderConfirm extends DataModel<UpgradeOrderConfirm> {
  constructor() {
    super(UpgradeOrderConfirm, '升级订单确认');
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      order: {
        clientSide: 'object',
        clientSideChildDataModel: UpgradeOrderItem,
        serverSide: 'undefined',
        clientSideRequired: true,
      },
      pay: {
        clientSide: 'object',
        clientSideChildDataModel: {
          convertTable: {
            appId: { clientSide: 'string', clientSideRequired: true },
            timeStamp: { clientSide: 'string', clientSideRequired: true },
            nonceStr: { clientSide: 'string', clientSideRequired: true },
            package: { clientSide: 'string', clientSideRequired: true },
            signType: { clientSide: 'string', clientSideRequired: true },
            paySign: { clientSide: 'string', clientSideRequired: true },
          },
        },
        serverSide: 'undefined',
      },
    };
  }

  order!: UpgradeOrderItem;
  pay?: {
    appId: string;
    timeStamp: string;
    nonceStr: string;
    package: string;
    signType: string;
    paySign: string;
  };
}

type GrowthLogSearch = {
  page?: number;
  pageSize?: number;
  keywords?: string;
  villageId?: number;
  userId?: number;
};

type PagedGrowthResponse = {
  total: number;
  per_page?: number;
  current_page?: number;
  last_page?: number;
  data: KeyValue[];
};

export type GrowthLogFeedType = 'task' | 'fruit' | 'light';

export type GrowthLogFeedItem =
  | { logType: 'task'; item: GrowthTaskLogItem }
  | { logType: 'fruit'; item: GrowthFruitLogItem }
  | { logType: 'light'; item: GrowthLightLogItem };

export class TreeApi extends AppServerRequestModule<DataModel> {
  constructor() {
    super();
  }

  private growthLogParams(search?: GrowthLogSearch) {
    return {
      page: search?.page,
      pageSize: search?.pageSize,
      keywords: search?.keywords,
      village_id: search?.villageId,
      user_id: search?.userId,
    };
  }

  private parsePagedList<T extends DataModel>(
    model: NewDataModel,
    data: PagedGrowthResponse,
    label: string,
  ) {
    return {
      total: data.total ?? 0,
      list: transformArrayDataModel<T>(model, transformSomeToArray(data.data), label, true),
    };
  }

  /** 将 total 随机拆成 parts 份（每份 ≥ 0，之和为 total） */
  private randomPartition(total: number, parts: number) {
    const buckets = Array.from({ length: parts }, () => 0);
    for (let i = 0; i < total; i++) {
      buckets[Math.floor(Math.random() * parts)]++;
    }
    return buckets;
  }

  private shuffle<T>(items: T[]) {
    const arr = [...items];
    for (let i = arr.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [arr[i], arr[j]] = [arr[j], arr[i]];
    }
    return arr;
  }

  private async fetchGrowthLogSlice<T extends DataModel>(
    url: string,
    label: string,
    model: NewDataModel,
    pageSize: number,
    search?: GrowthLogSearch,
    extra?: KeyValue,
  ) {
    if (pageSize <= 0) return [] as T[];
    const res = await this.post<PagedGrowthResponse>(url, label, {
      ...this.growthLogParams({ ...search, page: 1, pageSize }),
      ...extra,
    });
    return this.parsePagedList<T>(model, res.requireData(), label).list;
  }

  /**
   * 聚合随机成长流水：将 count 随机分配到任务日志 / 乡源果 / 乡源光三个接口并行拉取，打乱后返回。
   */
  async getRandomGrowthLogFeed(
    count: number,
    search?: GrowthLogSearch & {
      fruitType?: 'pick' | 'task' | 'bless' | 'exchange' | string;
      lightType?: 'water' | 'fertilize' | 'task' | 'bless' | string;
    },
  ) {
    if (count <= 0) {
      return { list: [] as GrowthLogFeedItem[], total: 0 };
    }

    const [taskCount, fruitCount, lightCount] = this.randomPartition(count, 3);

    const [taskList, fruitList, lightList] = await Promise.all([
      this.fetchGrowthLogSlice<GrowthTaskLogItem>(
        '/village/growth/taskLogList',
        '任务日志',
        GrowthTaskLogItem,
        taskCount,
        search,
      ),
      this.fetchGrowthLogSlice<GrowthFruitLogItem>(
        '/village/growth/fruitLogList',
        '乡源果流水',
        GrowthFruitLogItem,
        fruitCount,
        search,
        { type: search?.fruitType },
      ),
      this.fetchGrowthLogSlice<GrowthLightLogItem>(
        '/village/growth/lightLogList',
        '乡源光流水',
        GrowthLightLogItem,
        lightCount,
        search,
        { type: search?.lightType },
      ),
    ]);

    const merged: GrowthLogFeedItem[] = [
      ...taskList.map((item) => ({ logType: 'task' as const, item })),
      ...fruitList.map((item) => ({ logType: 'fruit' as const, item })),
      ...lightList.map((item) => ({ logType: 'light' as const, item })),
    ];

    const list = this.shuffle(merged).slice(0, count);
    return { list, total: list.length };
  }

  /** 任务日志列表 */
  async getTaskLogList(search?: GrowthLogSearch) {
    const res = await this.post<PagedGrowthResponse>(
      '/village/growth/taskLogList',
      '任务日志列表',
      this.growthLogParams(search),
    );
    return this.parsePagedList<GrowthTaskLogItem>(
      GrowthTaskLogItem,
      res.requireData(),
      '任务日志',
    );
  }

  /** 乡源果流水 */
  async getFruitLogList(
    search?: GrowthLogSearch & {
      type?: 'pick' | 'task' | 'bless' | 'exchange' | string;
    },
  ) {
    const res = await this.post<PagedGrowthResponse>(
      '/village/growth/fruitLogList',
      '乡源果流水',
      {
        ...this.growthLogParams(search),
        type: search?.type,
      },
    );
    return this.parsePagedList<GrowthFruitLogItem>(
      GrowthFruitLogItem,
      res.requireData(),
      '乡源果流水',
    );
  }

  /** 乡源光流水 */
  async getLightLogList(
    search?: GrowthLogSearch & {
      type?: 'water' | 'fertilize' | 'task' | 'bless' | string;
    },
  ) {
    const res = await this.post<PagedGrowthResponse>(
      '/village/growth/lightLogList',
      '乡源光流水',
      {
        ...this.growthLogParams(search),
        type: search?.type,
      },
    );
    return this.parsePagedList<GrowthLightLogItem>(
      GrowthLightLogItem,
      res.requireData(),
      '乡源光流水',
    );
  }

  /** 赐福套餐列表 */
  async getBlessList(options?: {
    page?: number;
    pageSize?: number;
    keywords?: string;
  }) {
    const res = await this.post<PagedGrowthResponse>(
      '/village/growth/blessList',
      '赐福套餐列表',
      {
        page: options?.page,
        pageSize: options?.pageSize,
        keywords: options?.keywords,
      },
    );
    return this.parsePagedList<BlessPackageItem>(
      BlessPackageItem,
      res.requireData(),
      '赐福套餐',
    );
  }

  /** 赐福订单列表 */
  async getBlessOrders(options?: {
    page?: number;
    pageSize?: number;
    keywords?: string;
    villageId?: number;
    userId?: number;
    blessId?: number;
    /** -1=已取消, 0=待支付, 1=已支付 */
    status?: -1 | 0 | 1 | number;
  }) {
    const res = await this.post<PagedGrowthResponse>(
      '/village/growth/blessOrders',
      '赐福订单列表',
      {
        page: options?.page,
        pageSize: options?.pageSize,
        keywords: options?.keywords,
        village_id: options?.villageId,
        user_id: options?.userId,
        bless_id: options?.blessId,
        status: options?.status,
      },
    );
    return this.parsePagedList<BlessOrderItem>(
      BlessOrderItem,
      res.requireData(),
      '赐福订单',
    );
  }

  /** 升级套餐列表 */
  async getUpgradeList(options?: {
    page?: number;
    pageSize?: number;
    keywords?: string;
  }) {
    const res = await this.post<PagedGrowthResponse>(
      '/village/growth/upgradeList',
      '升级套餐列表',
      {
        page: options?.page,
        pageSize: options?.pageSize,
        keywords: options?.keywords,
      },
    );
    return this.parsePagedList<UpgradePackageItem>(
      UpgradePackageItem,
      res.requireData(),
      '升级套餐',
    );
  }

  /** 升级套餐详情 */
  async getUpgradeInfo(id: number) {
    const res = await this.post<KeyValue>('/village/growth/upgradeInfo', '升级套餐详情', { id });
    return transformDataModel<UpgradePackageItem>(UpgradePackageItem, res.requireData());
  }

  private getStringDataOrMessage(res: RequestApiResult<any>) {
    return typeof res.data === 'string' ? res.data : res.message;
  }

  /** 浇水（每日限次，仅可关注或认领的村社） */
  async water(villageId: number) {
    const res = await this.post<null>('/village/growth/water', '浇水', {
      village_id: villageId,
    });
    return this.getStringDataOrMessage(res);
  }

  /** 施肥（每日限次，仅可关注或认领的村社） */
  async fertilize(villageId: number) {
    const res = await this.post<null>('/village/growth/fertilize', '施肥', {
      village_id: villageId,
    });
    return this.getStringDataOrMessage(res);
  }

  /** 拾取果子 */
  async pick(villageId: number) {
    const res = await this.post<null>('/village/growth/pick', '拾取果子', {
      village_id: villageId,
    });
    return this.getStringDataOrMessage(res);
  }

  /** 乡源树产果（随机产果，返回可拾取数量） */
  async dropFruit(villageId: number) {
    const res = await this.post<KeyValue>('/village/growth/dropFruit', '乡源树产果', {
      village_id: villageId,
    });
    return transformDataModel<DropFruitResult>(DropFruitResult, res.requireData());
  }

  /** 下单赐福套餐 */
  async createBlessOrder(villageId: number, blessId: number) {
    const res = await this.post<KeyValue>('/village/growth/bless', '下单赐福', {
      village_id: villageId,
      bless_id: blessId,
    });
    const data = res.requireData();
    return transformDataModel<BlessOrderConfirm>(BlessOrderConfirm, data);
  }

  /**
   * 发放赐福奖励（支付成功后调用；文档未列参数，按订单 id 发放）
   * @param id 赐福订单 ID（`createBlessOrder` 返回的 id）
   */
  async grantBlessReward(id: number) {
    const res = await this.post<null>('/village/growth/grantBlessReward', '发放赐福奖励', { id });
    return res.requireData();
  }

  /** 升级订单列表 */
  async getUpgradeOrderList(options?: {
    page?: number;
    pageSize?: number;
    keywords?: string;
    villageId?: number;
    userId?: number;
    /** -1=已取消, 0=未支付, 1=已支付, 2=待审核（对公付款审核凭证） */
    status?: -1 | 0 | 1 | 2 | number;
  }) {
    const res = await this.post<PagedGrowthResponse>(
      '/village/growth/upgradeOrderList',
      '升级订单列表',
      {
        page: options?.page,
        pageSize: options?.pageSize,
        keywords: options?.keywords,
        village_id: options?.villageId,
        user_id: options?.userId,
        status: options?.status,
      },
    );
    return this.parsePagedList<UpgradeOrderItem>(
      UpgradeOrderItem,
      res.requireData(),
      '升级订单',
    );
  }

  /** 升级订单详情 */
  async getUpgradeOrderInfo(id: number) {
    const res = await this.post<KeyValue>('/village/growth/upgradeOrderInfo', '升级订单详情', { id });
    return transformDataModel<UpgradeOrderItem>(UpgradeOrderItem, res.requireData());
  }

  /** 升级订单下单 */
  async createUpgradeOrder(
    villageId: number,
    upgradeLevelId: number,
    payType: 1 | 2,
  ) {
    const res = await this.post<KeyValue>('/village/growth/upgrade', '升级订单下单', {
      village_id: villageId,
      upgrade_level_id: upgradeLevelId,
      pay_type: payType,
    });
    return transformDataModel<UpgradeOrderConfirm>(UpgradeOrderConfirm, res.requireData());
  }

  /** 对公付款上传凭证 */
  async saveUpgrade(id: number, payVoucher: string) {
    const res = await this.post<null>('/village/growth/saveUpgrade', '提交升级订单凭证', {
      id,
      pay_voucher: payVoucher,
    });
    return this.getStringDataOrMessage(res);
  }
}

export default new TreeApi();
