import { DataModel, transformArrayDataModel, type NewDataModel } from '@imengyu/js-request-transform';
import ApiCofig from '@/common/config/ApiCofig';
import { AppServerRequestModule } from './RequestModules';
import { transformSomeToArray } from './Utils';
import { assertNotNull, RequestApiConfig, RequestOptions, type QueryParams } from '@imengyu/imengyu-utils';

export class GetColumListParams extends DataModel<GetColumListParams> {
  
  public constructor() {
    super(GetColumListParams);
    this.setNameMapperCase('Camel', 'Snake');
  }

  setModelId(val: number) {
    this.modelId = val;
    return this;
  }
  setMainBodyColumnId(val: number) {
    this.mainBodyColumnId = val;
    return this;
  }
  setFlag(val: 'hot'|'recommend'|'top') {
    this.flag = val;
    return this; 
  }
  setSize(val: number) {
    this.size = val;
    return this; 
  }

  modelId?: number;
  /**
   * 	主体栏目id
   */
  mainBodyColumnId: number = 0;
  /**
   * 标志：hot=热门，recommend=推荐，top=置顶
   */
  flag ?: 'hot'|'recommend'|'top';
  /**
   * 内容数量，默认4
   */
  size = 4;
}
export class GetContentListParams extends DataModel<GetContentListParams> {
  
  public constructor() {
    super(GetContentListParams);
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      ids: {
        customToServerFn: (val) => (val as number[]).join(','),
        customToClientFn: (val) => (val as string).split(',').map((item) => parseInt(item)),
      },
    }
  }


  setMainBodyColumnId(val: number|number[]) {
    this.mainBodyColumnId = val;
    return this;
  }
  setFlag(val: 'hot'|'recommend'|'top') {
    this.flag = val;
    return this; 
  }
  setIds(val: number[]) {
    this.ids = val;
    return this; 
  }
  setType(val: 1|2|3|4) {
    this.type = val;
    return this;
  }
  setSize(val: number) {
    this.size = val;
    return this;
  }
  setKeywords(val: string) {
    this.keywords = val;
    return this; 
  }
  setModelId(val: number) {
    this.modelId = val;
    return this; 
  }

  static TYPE_ARTICLE = 1;
  static TYPE_AUDIO = 2;
  static TYPE_VIDEO = 3;
  static TYPE_IMAGE = 4;

  modelId ?: number;
  /**
   * 主体栏目id
   */
  mainBodyColumnId: number|number[] = 0;
  /**
   * 标志：hot=热门，recommend=推荐，top=置顶
   */
  flag ?: 'hot'|'recommend'|'top';
  /**
   * 内容id（逗号隔开）如：3 或者 1,2,3
   */
  ids?: number[];
  /**
   * 类型：1=文章，2=音频，3=视频，4=相册
   */
  type?: 1|2|3|4;
  /**
   * 内容数量，默认4
   */
  size = 4;
  /**
   * 关键字查询
   */
  keywords?: string;

}

export class GetColumContentList extends DataModel<GetColumContentList> {
  constructor() {
    super(GetColumContentList, "主体栏目列表");
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      name: { clientSide: 'string', serverSide: 'string', clientSideRequired: true },
      content_list: { 
        clientSide: 'array',
        clientSideRequired: true,
        clientSideChildDataModel: GetContentListItem,
      },
    }
  }

  name = '';
  overview = '';
}
export class GetContentListItem extends DataModel<GetContentListItem> {
  constructor() {
    super(GetContentListItem, "内容列表");
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      mainBodyColumnId: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      title: { clientSide: 'string', serverSide: 'string', clientSideRequired: true },
      isGuest: { clientSide: 'boolean', serverSide: 'number' },
      isLogin: { clientSide: 'boolean', serverSide: 'number' },
      isComment: { clientSide: 'boolean', serverSide: 'number' },
      isLike: { clientSide: 'boolean', serverSide: 'number' },
      isCollect: { clientSide: 'boolean', serverSide: 'number' },
      latitude: { clientSide: 'number', serverSide: 'number' },
      longitude: { clientSide: 'number', serverSide: 'number' },
      publishAt: { clientSide: 'date', serverSide: 'string' },
      flag: { clientSide: 'splitCommaArray', serverSide: 'commaArrayMerge' },
      tags: { clientSide: 'splitCommaArray', serverSide: 'commaArrayMerge' },
      keywords: { clientSide: 'splitCommaArray', serverSide: 'commaArrayMerge' },
      type: { clientSide: 'number', serverSide: 'number' },
    };
    this._convertKeyType = (key, direction) => {
      if (key.endsWith('Time'))
        return {
          clientSide: 'date',
          serverSide: 'string',
        };
      return undefined;
    };
  }
  id = 0;
  mainBodyColumnId = 0;
  latitude = 0;
  longitude = 0;
  mapX = '';
  mapY = '';
  from = '';
  modelId = 0;
  title = '!title';
  region = 0;
  image = '';
  thumbnail = '';
  desc = '!desc';
  content = '!content';
  type = 0;
  keywords ?: string[];
  flag ?: string[];
  tags ?: string[];
  views = 0;
  comments = 0;
  likes = 0;
  collects = 0;
  dislikes = 0;
  district = '';
  publishAt = new Date();
}
export class GetContentDetailItem extends DataModel<GetContentDetailItem> {
  constructor() {
    super(GetContentDetailItem, "内容详情");
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      title: { clientSide: 'string', serverSide: 'string', clientSideRequired: true },
      isGuest: { clientSide: 'boolean', serverSide: 'number' },
      isLogin: { clientSide: 'boolean', serverSide: 'number' },
      isComment: { clientSide: 'boolean', serverSide: 'number' },
      isLike: { clientSide: 'boolean', serverSide: 'number' },
      isCollect: { clientSide: 'boolean', serverSide: 'number' },
      publishAt: { clientSide: 'date', serverSide: 'string' },
      flag: { clientSide: 'splitCommaArray', serverSide: 'commaArrayMerge' },
      tags: { clientSide: 'splitCommaArray', serverSide: 'commaArrayMerge' },
      type: { clientSide: 'number', serverSide: 'number' },
    }
    this._convertKeyType = (key, direction) => {
      if (key.endsWith('Time'))
        return {
          clientSide: 'date',
          serverSide: 'string',
        };
      else if (key.endsWith('List')) {
        return [
          { clientSide: 'map', serverSide: 'original'},
          { clientSide: 'array', clientSideChildDataModel: GetContentDetailItem, serverSide: 'original' },
        ]
      }
      return undefined;
    };
    this._afterSolveServer = () => {
      if (!this.image && this.images && this.images && this.images.length > 0  ) {
        this.image = this.images[0]
      }
      if ((!this.images || this.images.length == 0) && this.image) {
        this.images = [ this.image ]
      }
    }
  }

  id = 0;
  from = '';
  modelId = 0;
  type = 0;
  title = '';
  region = 0;
  image = '';
  images = [] as string[];
  audio = '';
  video = '';
  desc = '';
  flag ?: string[];
  tags ?: string[];
  views = 0;
  comments = 0;
  likes = 0;
  collects = 0;
  dislikes = 0;
  isLogin = false;
  isGuest = false;
  isComment = false;
  isLike = false;
  isCollect = false;
  content = '';
  publishAt = new Date();
  associationMeList = [] as {
    id: number,
    title: string,
    image: string,
    thumbnail: string,
  }[];
}

export class CategoryListItem extends DataModel<CategoryListItem> {
  constructor() {
    super(CategoryListItem, "分类列表");
    this.setNameMapperCase('Camel', 'Snake');
    this._convertTable = {
      id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
      pid: { clientSide: 'number', serverSide: 'number' },
      haschild: { clientSide: 'boolean', serverSide: 'number' },
    }
  }

  id !: number;
  pid !: number;
  title = '';
  status = 'normal';
  weight = 0;
  spacer = '';
  haschild = false;
  children?: CategoryListItem[];
}

/**
 * 说明：
 * * 主通用内容接口。
 */
export class CommonContentApi extends AppServerRequestModule<DataModel> {

  constructor(
    mainBodyId = ApiCofig.mainBodyId, 
    modelId = 0, debugName = 'CommonContent', 
    mainBodyColumnId?: number|number[]) {
    super();
    this.modelId = modelId;
    this.mainBodyId = mainBodyId;
    this.mainBodyColumnId = mainBodyColumnId;
    this.debugName = debugName;
  }

  public mainBodyId: number;
  public mainBodyColumnId?: number|number[];
  public modelId: number;
  protected debugName: string;

  private toStringArray(arr: number|number[]|undefined) {
    if (typeof arr === 'undefined') 
      return '';
    return typeof arr === 'object' ? arr.join(',') : arr.toString();
  }

  /**
   * 获取分类列表
   * @param type 根级类型：1=区域、2=级别、3=文物类型、4=非遗类型、42=事件类型
   * @param withself 是否返回包含自己：true=是，false=否 ，默认false
   * @returns 
   */
  async getCategoryList(
    type?: number,
    withself?: boolean,
  ) {
    const res = await this.get<any[]>('/content/category/getCategoryList', '获取分类列表', {
      type,
      is_tree: false,
      withself,
    });
    return transformArrayDataModel<CategoryListItem>(CategoryListItem, res.requireData(), `获取分类列表`, true);
  }
  /**
   * 用于获取某一个分类需要用的子级
   * @param pid 父级
   * @returns 
   */
  async getCategoryChildList(pid?: number) {
    const res = await this.get('/content/category/getCategoryOnlyChildList', '获取分类子级列表', {
      pid,
    });
    return transformArrayDataModel<CategoryListItem>(
      CategoryListItem, 
      transformSomeToArray(res.data), 
      `获取分类列表`, 
      true
    );
  }
  /**
   * 地址下拉带搜索
   * @param pid 父级
   * @returns 
   */
  async searchRegion(keywords?: string) {
    const res = await this.get('/content/category/searchRegion', '地址搜索', {
      keywords,
    });
    return transformArrayDataModel<CategoryListItem>(
      CategoryListItem, 
      transformSomeToArray(res.data), 
      `地址下拉带搜索`, 
      true
    );
  }
  /**
   * 主体栏目列表
   * @param params 参数 
   * @param querys 额外参数
   * @returns 
   */
  async getColumList<T extends DataModel = GetColumContentList>(params: GetColumListParams, modelClassCreator: NewDataModel = GetColumContentList, querys?: QueryParams) {
    const res = await this.get<{
      list: T[],
      total: number,
    }>('/content/content/getMainBodyColumnContentList', `${this.debugName} 主体栏目列表`, {
      main_body_id: this.mainBodyId,
      model_id: this.modelId,
      ...params.toServerSide(),
      ...querys,
    });
    assertNotNull(res.data, '获取主体栏目列表失败');
    return {
      list: transformArrayDataModel<T>(modelClassCreator, res.data.list, `${this.debugName} 主体栏目列表`, true),
      total: res.data.total as number,
    };
  }
  /**
   * 模型内容列表
   * @param params 参数
   * @param page 页码
   * @param pageSize 页大小
   * @param querys 额外参数
   * @returns 
   */
  async getContentList<T extends DataModel = GetContentListItem>(
    params: GetContentListParams, 
    page: number, 
    pageSize: number = 10, 
    modelClassCreator: NewDataModel = GetContentListItem, 
    isNearby?: boolean,
    querys?: QueryParams
  ) {
    const res = await this.get<{
      list: any[],
      total: number,
    }>(`/content/content/${isNearby ? 'getNearbyList' : 'getContentList'}`, `${this.debugName} 模型内容列表`, {
      ...params.toServerSide(),
      model_id: params.modelId || this.modelId,
      main_body_id: params.mainBodyId || this.mainBodyId,
      main_body_column_id: this.toStringArray(params.mainBodyColumnId || this.mainBodyColumnId),
      page,
      pageSize,
      ...querys,
    });
    let resList : any = null;
    let resTotal : any = null;

    if (res.data?.list && Array.isArray(res.data.list)) {
      resList = res.data.list;
      resTotal = res.data.total ?? resList.length;
    }
    else if (res.data && Array.isArray(res.data)) {
      resList = res.data;
      resTotal = resList.length;
    } else
      resList = res.data;

    if (resList === null)
      return { list: [], total: 0 };
    
    return { 
      list: transformArrayDataModel<T>(modelClassCreator, resList, `${this.debugName} 模型内容列表`, true),
      total: resTotal as number,
    };
  }
  /**
   * 内容详情
   * @param id id 
   * @param querys 额外参数
   * @returns 
   */
  async getContentDetail<T extends DataModel = GetContentDetailItem>(id: number, modelClassCreator: NewDataModel = GetContentDetailItem, modelId?: number, querys?: QueryParams) {
    return (await this.get('/content/content/getContentDetail', `${this.debugName} (${id}) 内容详情`, {
      main_body_id: this.mainBodyId,
      model_id: modelId ?? this.modelId,
      id,
      ...querys,
    }, modelClassCreator)).data as T;
  }
  /**
   * 上传文件到服务器
   */
  async uploadFile(file: string, fileType?: "image" | "video" | "audio" | undefined, name = 'file', data?: any, receiveTask?: (result: UniApp.UploadTask) => void) {
    let url = RequestApiConfig.getConfig().BaseUrl + '/common/upload';
    let req : RequestOptions = {
      method: 'POST',
      data: data,
      headers: {},
    }
    if (this.config.requestInterceptor) {
      const { newReq, newUrl } = await this.config.requestInterceptor(url, req);
      url = newUrl;
      data = newReq;
    }
    return new Promise<{
      fullurl: string,
      url: string
    }>((resolve, reject) => {
      const task = uni.uploadFile({
        url: url,
        name,
        header: req.headers,
        filePath: file,
        formData: data,
        fileType,
        success: (result) => {
          let data = JSON.parse(result.data);
          if (data.code !== 1)
            throw new Error(data.msg ?? 'code: ' + data.code);
          resolve(data.data);
        },
        fail(result) {
          reject(result);
        },
      })
      if (receiveTask)
        receiveTask(task);
    })
  }

  /**
   * 上传图片
   * @param tempFilePath 临时文件路径
   * @returns 
   */
  async uploadImages(tempFilePath: string) {
    const res = await this.uploadFile(tempFilePath, 'image');
    return res.fullurl;
  }
}

export default new CommonContentApi(undefined, 0, '默认通用内容');