import {StaticResponse} from 'cypress/types/net-stubbing';
import menuJson from '../../fixtures/menu/basic.json';

/** 点击select具体项 */
export function selectClick(testid: string, eq = 0) {
  cy.getTestId(testid).click();
  cy.getTestId(testid)
    .find('.rc-virtual-list-holder-inner')
    .children('.ant-select-item')
    .eq(eq)
    .click();
}

/** 进入具体菜单 */
export function intoMenu(parent: string, child: string) {
  cy.wait('@loginIntercept');
  const list = menuJson.data;
  const menu = list.find(val => val.name === child);
  menu && cy.visit(menu);
}

export function clickMenu(parent: string, child: string) {
  cy.getTestId('menu')
    .children()
    .each(function (el) {
      const titleElement = el.find('.ant-menu-submenu-title');

      if (titleElement.text() === parent) {
        titleElement.trigger('click');
        el.find(`ul>li[title="${child}"]`).trigger('click');
      }
    });
}

/** 校验select */
export function validateSelect(testid: string, value: string) {
  cy.getTestId(testid)
    .find('.ant-select-selection-item')
    .should('have.attr', 'title', value)
    .and('have.text', value);
}

/** 校验table内容 */
export function validateTableList(tableName: string) {
  cy.getTestId(tableName)
    .find('table')
    .find('.ant-table-tbody')
    .children('.ant-table-row')
    .first()
    .find('td')
    .eq(1)
    .should('have.text', 'page-1');

  cy.getTestId(tableName)
    .siblings('.ant-pagination')
    .find('li[title="2"]')
    .click();

  cy.getTestId(tableName)
    .find('table')
    .find('.ant-table-tbody')
    .children('.ant-table-row')
    .first()
    .find('td')
    .eq(1)
    .should('have.text', 'page-2');
}

/** 选择时间组件 */
export function clickDatePicker(id: string) {
  cy.getTestId(id).click();

  cy.get('.ant-picker-panels')
    .children()
    .eq(0)
    .find('.ant-picker-content')
    .find('tbody')
    .find('td')
    .eq(0)
    .click();

  cy.get('.ant-picker-panels')
    .children()
    .eq(1)
    .find('.ant-picker-content')
    .find('tbody')
    .find('td')
    .eq(0)
    .click();
}

/** 校验table search */
export function validateTableSearch(
  tableName: string,
  keys: (
    | {
        id: string;
        type: 'select';
        value: string;
        eq?: number;
        defaultValue?: string;
      }
    | {id: string; type: 'date'}
    | string
  )[],
  options: {
    toolId: string;
    url: string;
  },
) {
  const {toolId, url} = options;

  cy.getTestId(tableName)
    .siblings('.ant-pagination')
    .find('li[title="2"]')
    .click();

  function clear(data?: (typeof keys)[0]) {
    function clearData(key: (typeof keys)[0]) {
      if (typeof key === 'string') {
        cy.getTestId(toolId).find(`[data-testid="filter_${key}"]`).clear();
      } else {
        const {id, type} = key;
        const clearId =
          type === 'select' ? '.ant-select-clear' : '.ant-picker-clear';

        cy.getTestId(toolId)
          .find(`[data-testid="filter_${id}"]`)
          .trigger('mouseover')
          .find(clearId)
          .click();
      }
    }

    if (data) {
      return clearData(data);
    }

    keys.forEach(clearData);
  }

  function validate(text: string, reset?: boolean) {
    !reset && cy.getTestId(toolId).find('[data-testid="search_btn"]').click();

    cy.getTestId(toolId)
      .find('[data-testid="search_btn"]')
      .should('have.class', 'ant-btn-loading');

    cy.getTestId(tableName)
      .find('table')
      .find('.ant-table-tbody')
      .children('.ant-table-row')
      .first()
      .find('td')
      .eq(1)
      .should('have.text', text);

    cy.getTestId(tableName)
      .siblings('.ant-pagination')
      .find('li[title="1"]')
      .should('have.class', 'ant-pagination-item-active');

    cy.getTestId(toolId)
      .getTestId('search_btn')
      .should('not.have.class', 'ant-btn-loading');
  }

  function eachAllField(skipValidate = false) {
    keys.forEach(function (key, idx) {
      if (idx > 0 && !skipValidate) {
        clear(keys[idx - 1]);
      }
      let validateText: string;

      if (typeof key === 'string') {
        cy.getTestId(toolId).find(`[data-testid="filter_${key}"]`).type(key);
        validateText = key;
      } else {
        const {id, type} = key;
        switch (type) {
          case 'select':
            selectClick(`filter_${id}`, key?.eq ?? 0);
            validateText = key.value;
            break;
          case 'date':
            clickDatePicker(`filter_${id}`);
            validateText = 'searchTime';
            break;
        }
      }
      !skipValidate && validate(validateText);
    });
  }

  eachAllField();

  // 校验重置功能
  eachAllField(true);
  cy.getTestId(toolId).find('[data-testid="reset_btn"]').click();
  keys.forEach(function (key) {
    if (typeof key === 'string') {
      cy.getTestId(`filter_${key}`).invoke('val').should('be.empty');
    } else {
      switch (key.type) {
        case 'select':
          if (key.defaultValue) {
            validateSelect(`filter_${key.id}`, key.defaultValue);
            break;
          }
          cy.getTestId(`filter_${key.id}`)
            .find('.ant-select-selection-placeholder')
            .should('exist');
          break;
        case 'date':
          cy.getTestId(`filter_${key.id}`)
            .children('.ant-picker-input')
            .first()
            .find('input')
            .invoke('val')
            .should('be.empty');
          cy.getTestId(`filter_${key.id}`)
            .children('.ant-picker-input')
            .last()
            .find('input')
            .invoke('val')
            .should('be.empty');
          break;
      }
    }
  });
  validate('page-1', true);

  // 校验刷新功能
  cy.getTestId(tableName)
    .closest('.ant-card-body')
    .find('[data-testid="refresh_btn"]')
    .click();
  cy.getTestId(tableName)
    .closest('.ant-card-body')
    .find('[data-testid="refresh_btn"]')
    .should('have.class', 'ant-btn-loading');
  cy.wait(`@${url}`);
  cy.getTestId(tableName)
    .closest('.ant-card-body')
    .find('[data-testid="refresh_btn"]')
    .should('not.have.class', 'ant-btn-loading');
}

/** 表格内按钮点击 */
export function tableBtnClick(tableName: string, index: number) {
  function getBtn() {
    return cy
      .getTestId(tableName)
      .find('table')
      .find('.ant-table-tbody')
      .children('.ant-table-row')
      .first()
      .find('td')
      .last()
      .children()
      .eq(index);
  }

  getBtn().click();

  return getBtn;
}

/** 弹窗按钮校验 */
export function validateModalBtnGroup(modalName: string) {
  cy.getTestId(modalName)
    .getTestId('modal_btn_group')
    .find('.ant-btn')
    .should('have.class', 'ant-btn-loading');
}

// 校验antd message内容
export function validateMessageContent(msg: string) {
  cy.get('.ant-message-notice-content').should('include.text', msg);
}

// 校验modal的操作结果
export function validateModalOperation(modalName: string, text: string) {
  cy.getTestId(modalName).find('form').submit();

  validateModalBtnGroup(modalName);
  validateMessageContent(text);
  cy.getTestId(modalName).should('not.exist');
}

/** 校验新增或修改事件 */
export function validatePut(
  modalName: string,
  tableName: string,
  options: {label: string},
) {
  const {label} = options;

  function validateAdd(
    keys: (
      | string
      | {id: string; type: 'select'}
      | {id: string; type: 'keySelect'}
      | {id: string; type: 'field'; value: string}
    )[],
  ) {
    cy.getTestId(tableName)
      .closest('.ant-card-body')
      .find('[data-testid="add_btn"]')
      .click();

    cy.getTestId(modalName).should('exist').and('be.visible');
    cy.getTestId(modalName).find('h3').should('have.text', `新增${label}`);

    keys.forEach(function (key) {
      if (typeof key === 'string') {
        cy.getTestId(`field_${key}`).type(key);
      } else {
        const {type, id} = key;

        switch (type) {
          case 'select':
            selectClick(`field_${id}`, 0);
            break;
          case 'field':
            cy.getTestId(`field_${id}`).clear().type(key.value);
            break;
          case 'keySelect':
            cy.get(`#field_${id}`).clear().type(id);
            selectClick(`field_${id}`, 0);
            break;
        }
      }
    });

    validateModalOperation(modalName, '新增成功');
  }

  function validateEdit(
    keys: {id: string; type: 'field' | 'select'; value: string}[],
    eq = 0,
  ) {
    tableBtnClick(tableName, eq);

    cy.getTestId(modalName).should('exist').and('be.visible');
    cy.getTestId(modalName).find('h3').should('include.text', `修改${label}`);

    keys.forEach(function ({id, type, value}) {
      switch (type) {
        case 'field':
          cy.getTestId(`field_${id}`).should('have.value', value);
          break;
        case 'select':
          validateSelect(`field_${id}`, value);
          break;
      }
    });

    validateModalOperation(modalName, '修改成功');
  }

  return {validateAdd, validateEdit};
}

/** 校验antd dialog信息 */
export function validateDialog(
  title: string,
  content: string,
  options?: {confirm?: boolean},
) {
  const {confirm = true} = options ?? {};

  cy.get('.ant-modal-confirm-title').should('include.text', title);
  cy.get('.ant-modal-confirm-content').should('include.text', content);
  cy.get('.ant-modal-confirm-btns')
    .children()
    .eq(confirm ? 1 : 0)
    .click();
}

/** 校验删除 */
export function validateDelete(
  tableName: string,
  label: string,
  options: {eq?: number; title: string},
) {
  const {eq = 1, title} = options;
  tableBtnClick(tableName, eq);

  cy.get('.ant-modal-content').should('be.visible');

  validateDialog(title, `你确定要删除当前${label}吗？`);

  // 删除按钮在加载
  cy.getTestId(tableName)
    .find('table')
    .find('.ant-table-tbody')
    .children('.ant-table-row')
    .first()
    .find('td')
    .last()
    .children()
    .eq(eq)
    .should('have.class', 'ant-btn-loading');

  // 其他按钮禁用
  cy.getTestId(tableName)
    .find('table')
    .find('.ant-table-tbody')
    .children('.ant-table-row')
    .first()
    .find('td')
    .last()
    .children()
    .each(function (el, idx) {
      if (idx !== eq) {
        expect(el).to.have.attr('disabled');
      }
    });

  validateMessageContent('删除成功');
}

/** 校验导出 */
export function validateExport(tableName: string) {
  cy.getTestId(tableName)
    .closest('.ant-card-body')
    .find('[data-testid="export_btn"]')
    .click();

  cy.getTestId(tableName)
    .closest('.ant-card-body')
    .find('[data-testid="export_btn"]')
    .should('have.class', 'ant-btn-loading');

  cy.getTestId(tableName)
    .closest('.ant-card-body')
    .find('[data-testid="export_btn"]')
    .should('not.have.class', 'ant-btn-loading');
}

/** 关闭modal */
export function closeModal() {
  cy.get('.ReactModal__Overlay').trigger('click', 'topRight');
}

/** 选择所有的筛选框 */
export function selectAllFilters(toolId: string, count: number) {
  cy.getTestId(toolId).getTestId('filter_btn').click();
  cy.get('.ant-transfer')
    .find('.ant-transfer-list')
    .first()
    .find('.ant-transfer-list-header')
    .find('input[type="checkbox"]')
    .check();
  cy.get('.ant-transfer')
    .find('.ant-transfer-operation')
    .find('button')
    .first()
    .click();
  cy.getTestId('filter_select_modal').find('form').submit();

  cy.getTestId(toolId)
    .children('.ant-space')
    .first()
    .children()
    .should('have.length', count + 1);
}

/** 生成返回内容 */
export function generateResult<T extends Record<string, any>>(
  data: T,
  length: number,
  options: {
    limit: string;
    key?: string;
    isList?: boolean;
    title?: keyof T;
    value?: string;
  },
) {
  const {key = 'id', isList = false, title, value, limit} = options;

  const result = Array.from({length: Number(limit)}, function (_, idx) {
    const temp = {...data, [key]: idx + 1};

    return title ? {...temp, [title]: value ?? ''} : temp;
  });

  return {msg: '200', data: isList ? {total: length, list: result} : result};
}

/** 生成请求结果 */
export function generateNetworkResult<
  T extends Record<string, unknown>,
>(options: {
  search: URLSearchParams;
  basicData: T;
  reply: (params: StaticResponse) => void;
  title: keyof T;
  skipCondition?: (name: string) => boolean;
  replaceValue?: string;
}) {
  const {
    search,
    basicData,
    reply,
    title,
    skipCondition = () => false,
    replaceValue,
  } = options;

  const page = search.get('page'),
    limit = search.get('limit');

  for (const [name, searchValue] of search.entries()) {
    if (
      name === 'page' ||
      name === 'limit' ||
      name === 'id' ||
      skipCondition(name)
    )
      continue;

    if (searchValue) {
      return reply({
        body: generateResult(basicData, Number(limit) * 3, {
          limit,
          isList: true,
          title,
          value:
            name === 'startTime' || name === 'endTime'
              ? 'searchTime'
              : replaceValue ?? searchValue,
        }),
      });
    }
  }

  if (search.has('id') && search.get('id').length > 0) {
    return reply({
      body: generateResult(basicData, 1, {limit: '1', isList: true}),
    });
  }

  reply({
    body: generateResult(basicData, Number(limit) * 3, {
      limit,
      isList: true,
      title,
      value: replaceValue ?? `page-${page}`,
    }),
  });
}
