// @ts-nocheck 忽略所有类型检查

import type {
  BlockFile,
  BlockSchema,
  ExtensionConfig,
  HistoryItem,
  HistorySchema,
  MaterialDescription,
  NodeFromPlugin,
  ProjectSchema as OriginalProjectSchema,
  PageFile
} from '@vtj/core';

import {
  createFile,
  createHistory as createLowCodeHistory,
  deleteFile as deleteLowCodeFile,
  deleteHistory as deleteLowCodeHistory,
  getFile as getLowCodeFile,
  getHistories as getLowCodeHistories,
  getHistory as getLowCodeHistory,
  getMaterials as getLowCodeMaterials,
  getProject,
  postMaterials as postLowCodeMaterials,
  publishAllFile as publishLowCodeAllFile,
  publishFile as publishLowCodeFile,
  updateFile as updateLowCodeFile,
  updateMaterials as updateLowCodeMaterials,
  updateProject
} from '@/io';
// @ts-nocheck
import { HistoryModel, ProjectModel } from '@vtj/core';
import { BaseService } from '@vtj/renderer';
import { mapToObject, Storage } from '@vtj/utils';
import { isEmpty } from 'licia-es';

const storage = new Storage({
  type: 'local',
  expired: 0
});

const stringifyFields = new Set([
  'apis',
  'blocks',
  'config',
  'dependencies',
  'meta',
  'pages'
]);

// 扩展原始类型
type ProjectSchema = Omit<OriginalProjectSchema, 'projectId'> & {
  projectId: number | string;
};

let initProject: ProjectSchema;

export class LowCodeService extends BaseService {
  public api = (_type: string, _data: any): Promise<any> => {
    // console.log('api', type, data);
    return Promise.resolve(true);
  };

  public getExtension(): Promise<ExtensionConfig | undefined> {
    const extension = storage.get('extension');
    // console.log('ExtensionConfig', extension);
    return Promise.resolve(extension as ExtensionConfig | undefined);
  }

  public async getFile(id: string): Promise<BlockSchema> {
    return getLowCodeFile(id).then((lowCodeFile) => {
      return lowCodeFile.dsl
        ? Promise.resolve(lowCodeFile.dsl as BlockSchema)
        : Promise.reject(new Error('文件不存在'));
    });
  }
  public async getHistory(fileId: string): Promise<HistorySchema> {
    const histories = await getLowCodeHistories({
      project_id: initProject.id,
      file_id: fileId,
      per_page: 50
    });
    const formatDsl = {
      id: histories.list[0].file_id,
      items: histories.list.map((item) => {
        return {
          ...item,
          id: item.history_id,
          label: item.created_at
        };
      })
    };
    const history = new HistoryModel(formatDsl);
    return history.toDsl();
  }

  public async getHistoryItem(fId: string, id: string): Promise<HistoryItem> {
    const history = await getLowCodeHistory(id);
    return history;
  }

  public getPluginMaterial(
    _from: NodeFromPlugin
  ): Promise<MaterialDescription | null> {
    return Promise.resolve(null);
  }

  public async init(project: ProjectSchema): Promise<ProjectSchema> {
    initProject = project;
    const remoteProject = await getProject(initProject.id);
    const arrayFields = ['pages', 'blocks', 'apis', 'meta', 'dependencies'];
    arrayFields.forEach((field) => {
      if (isEmpty(remoteProject[field])) {
        remoteProject[field] = [];
      }
    });
    const model = new ProjectModel(remoteProject);
    const dsl = model.toDsl();
    return dsl;
  }

  public publish(project: ProjectSchema): Promise<boolean> {
    return publishLowCodeAllFile(Number(project.id)).then((res) => {
      return true;
    });
  }

  public publishFile(
    project: ProjectSchema,
    file: BlockFile | PageFile
  ): Promise<boolean> {
    return publishLowCodeFile(file.id).then((res) => {
      return true;
    });
  }

  public async removeFile(id: string): Promise<boolean> {
    return deleteLowCodeFile(id).then(() => true);
  }

  // TODO: 做成数据库存储后没啥用，保留就行
  public removeHistory(id: string): Promise<boolean> {
    // console.log('removeHistory', id);
    return Promise.resolve(true);
  }
  public async removeHistoryItem(fId: string, ids: string[]): Promise<boolean> {
    await Promise.all(ids.map((id) => deleteLowCodeHistory(id)));
    return true;
  }

  public async saveFile(file: BlockSchema): Promise<boolean> {
    if (file.id) {
      const existFile = await getLowCodeFile(file.id);
      return existFile.file_id
        ? updateLowCodeFile(file.id, {
            ...existFile,
            dsl: file
          })
            .then(() => {
              return true;
            })
            .catch((error) => {
              throw error;
            })
        : createFile({
            project_id: Number(initProject.id),
            publish: false,
            active: true,
            dsl: file,
            file_id: file.id
          })
            .then(() => {
              return true;
            })
            .catch((error) => {
              throw error;
            });
    }
    return false;
  }

  public async saveHistory(_history: HistorySchema): Promise<boolean> {
    return true;
  }

  public async saveHistoryItem(
    fileId: string,
    historyItem: HistoryItem
  ): Promise<boolean> {
    await createLowCodeHistory({
      project_id: initProject.id,
      file_id: fileId,
      history_id: historyItem.id,
      dsl: historyItem.dsl as HistorySchema
    });
    return true;
  }

  // TODO: 物料存储只有在发布为其他端 (比如 uinapp) 时才有用，当前版本时不需要的，暂且保留
  public async saveMaterials(
    project: ProjectSchema,
    materials: Map<string, MaterialDescription>
  ): Promise<boolean> {
    const materialData = mapToObject(materials);
    const existMaterials = await getLowCodeMaterials(project?.id);

    // 根据是否存在物料决定更新或创建
    existMaterials
      ? await updateLowCodeMaterials({
          project_id: project?.id,
          value: materialData
        })
      : await postLowCodeMaterials({
          project_id: project?.id,
          value: materialData
        });

    // @ts-ignore - 暂时禁用此行代码，保留以备后续可能需要删除物料的操作
    // await deleteLowCodeMaterials(project.id);
    return true;
  }
  public async saveProject(project: ProjectSchema): Promise<boolean> {
    const newProject = {
      ...project,
      ...Object.fromEntries(
        Object.entries(project)
          .filter(([key]) => stringifyFields.has(key))
          .map(([key, value]) => [key, JSON.stringify(value)])
      )
    };
    // 剔除引擎自行添加的 id，避免接口更新冲突报错
    Reflect.deleteProperty(newProject, 'id');
    await updateProject(initProject.id, newProject);
    return true;
  }

  protected uploader = (_file: File, _projectId: string): Promise<any> => {
    return Promise.resolve(true);
  };
}
