const Kuc = Kucs['1.19.0'];

const WEEK = ['日', '月', '火', '水', '木', '金', '土']

const monthItems = Array.from({ length: 12 }, (_, i) => {
  const month = "" + (i + 1);
  return { label: month, value: month.padStart(2, '0') };
});

const dateItems = Array.from({ length: 31 }, (_, i) => {
  const date = "" + (i + 1);
  return { label: date, value: date.padStart(2, '0') };
})
dateItems.push({ label: '末日', value: 'end' });

const classItems = [
  { label: "にじ", value: "にじ" },
  { label: "ほし", value: "ほし" },
  { label: "つき", value: "つき" },
  { label: "ゆり", value: "ゆり" },
]

const termItems = [
  { label: "０歳児", value: "０歳児" },
  { label: "１歳児", value: "１歳児" },
  { label: "２歳児", value: "２歳児" },
  { label: "３歳児", value: "３歳児" },
  { label: "４歳児", value: "４歳児" },
  { label: "５歳児", value: "５歳児" },
]

let notificationEl;
let loadingEl;
let dialogEl;

function getHeaderSpace(className, isDetailPage) {
  const headerSpace = (isDetailPage ? kintone.app.record : kintone.app).getHeaderMenuSpaceElement();
  if (!headerSpace) {
    throw new Error('このページではヘッダー要素が利用できません。');
  };

  const _className = isDetailPage ? 'customized-record-header-space' : 'customized-header-space';

  headerSpace.className += (' ' + _className + ' ' + className);
  headerSpace.parentElement.className += (' ' + _className + '-wrapper ' + className);

  return headerSpace;
}

function createBtnGroupArea(groupId, btnLabel, btnOnClick, { btnElId = false, yearElId = false, monthElId = false, dateElId = false, termElId = false, defaultThisMonth = false, }) {
  const result = {};

  if (document.getElementById(groupId)) {
    return;
  }

  const btnGroupAreaEl = document.createElement('div');
  btnGroupAreaEl.id = groupId;
  btnGroupAreaEl.className = 'btn-group-area'
  result[groupId] = btnGroupAreaEl;

  if (yearElId) {
    const yearEl = new Kuc.Text({
      value: "" + new Date().getFullYear(),
      id: yearElId,
      label: '年',
      className: 'year input'
    });
    result[yearElId] = yearEl;
    btnGroupAreaEl.appendChild(yearEl);
  }

  if (monthElId) {
    const monthEl = new Kuc.Combobox({
      value: defaultThisMonth ? monthItems[new Date().getMonth()].value : undefined,
      id: monthElId,
      className: 'month input',
      label: '月',
      items: monthItems,
    });
    result[monthElId] = monthEl;
    btnGroupAreaEl.appendChild(monthEl);
  }

  if (dateElId) {
    const dateEl = new Kuc.Combobox({
      value: dateItems[new Date().getDate() - 1].value,
      id: dateElId,
      items: dateItems,
      label: '日',
      className: "date input",
    });
    result[dateElId] = dateEl;
    btnGroupAreaEl.appendChild(dateEl);
  }

  if (termElId) {
    const termEl = new Kuc.Combobox({
      id: termElId,
      items: termItems,
      className: "term input",
      label: '学年',
    });
    result[termElId] = termEl;
    btnGroupAreaEl.appendChild(termEl);
  }

  const btnEl = new Kuc.Button({
    text: btnLabel,
    type: "submit",
    className: "action-btn",
    id: btnElId,
  });
  result[btnElId] = btnEl;
  btnEl.addEventListener('click', (e) => {
    showError(false);
    const checkResult = checkInputData(result, { btnLabel, yearElId, monthElId, dateElId, termElId });
    if (checkResult) {
      btnOnClick(e, checkResult);
    }
  });
  btnGroupAreaEl.appendChild(btnEl);

  return result;
}

function checkInputData(map, { btnLabel, yearElId, monthElId, dateElId, termElId }) {
  const year = yearElId && map[yearElId].value;
  const month = monthElId && map[monthElId].value;
  const date = dateElId && (map[dateElId].value === 'end' ? getLastDate(year, month).getDate() : map[dateElId].value);
  const term = termElId && map[termElId].value;

  const errorMsgs = [];

  if (yearElId) {
    const yearRegex = /^\d+$/;
    if (!yearRegex.test(year)) {
      errorMsgs.push(' · 年は整数で入力してください。');
    }
  }
  if (monthElId && !month) {
    errorMsgs.push(' · 月を選択してください。');
  }
  if (dateElId && !date) {
    errorMsgs.push(' · 日を選択してください。');
  }
  if (termElId && !term) {
    errorMsgs.push(' · 学年を選択してください。');
  }
  if (errorMsgs.length > 0) {
    showError(true, btnLabel + 'エラー\n' + errorMsgs.join('\n'))
    return;
  }

  return {
    year,
    month,
    date,
    term,
  }
}

function getLastDate(year, month) {
  // month は 1-12 の数値で入力する
  return new Date(year, month, 0);
}

function createBtn(id, label, onClick) {
  const btnEl = new Kuc.Button({
    text: label,
    type: "submit",
    className: "action-btn",
    id,
  });
  btnEl.addEventListener('click', onClick);
  return btnEl;
}

function hideSpaceField(ids) {
  ids.forEach(id => {
    const area = kintone.app.record.getSpaceElement(id);
    area.parentElement.style.minWidth = '0';
    area.parentElement.style.display = 'none';
  });
}

function getExcelName(excelName, nameSuffix = '', suffix = '.xlsx') {
  return excelName + (nameSuffix ? (nameSuffix.startsWith('_') ? nameSuffix : ('_' + nameSuffix)) : '') + suffix;
}

function getJapaneseEraDate(date = new Date()) {
  const formatter = new Intl.DateTimeFormat('ja-JP-u-ca-japanese', {
    era: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  });
  const japaneseDate = formatter.format(date);

  const match = japaneseDate.match(/(.+?)(元|\d+)年(\d+)月(\d+)日/);

  if (!match) {
    throw new Error("日付の解析に失敗しました。");
  }

  const era = match[1];
  const year = match[2] === "元" ? 1 : parseInt(match[2], 10);
  const month = parseInt(match[3], 10);
  const day = parseInt(match[4], 10);

  return {
    japaneseDate,
    era,
    year,
    month,
    day,
    westernYear: date.getFullYear()
  };
}

function convertToWesternYear(year, era) {
  return warekiStartYear[era] + year - 1;
}

function getYearRange() {
  const today = new Date();
  let year = today.getFullYear();
  if (today.getMonth() + 1 < 4) {
    year -= 1;
  }
  return {
    'start': getFormatDateString(year, 4, 1),
    'end': getFormatDateString(year + 1, 3, 31)
  }
}

function getFormatDateString(dateObjOrYear, month, date) {
  let year = dateObjOrYear;
  if (typeof dateObjOrYear === "object" && !month && !date) {
    year = dateObjOrYear.getFullYear();
    month = dateObjOrYear.getMonth() + 1;
    date = dateObjOrYear.getDate();
  }
  const formatY = year;
  const formatM = String(month).padStart(2, '0');
  const formatD = String(date).padStart(2, '0');

  return `${formatY}-${formatM}-${formatD}`;
}

function loading(show, text) {
  if (!loadingEl) {
    loadingEl = new Kuc.Spinner({
      container: document.querySelector('.container-gaia'),
      text
    });
  } else {
    loadingEl.close();
    loadingEl.text = text;
  }
  if (show) {
    loadingEl.open();
  }
}

function showError(show, text) {
  if (show) {
    buildNotification('danger', text);
    notificationEl.open();
    console.error(text);
  } else {
    notificationEl && notificationEl.close();
  }
}

function showSuccess(show, text, time = 3000) {
  if (show) {
    buildNotification('success', text, time);
    notificationEl.open();
  } else {
    notificationEl && notificationEl.close();
  }
}

function buildNotification(type, text, duration = -1) {
  const param = {
    type,
    text,
    duration
  }
  if (!notificationEl) {
    notificationEl = new Kuc.Notification(param);
  } else {
    Object.assign(notificationEl, param);
  }
}

/**
options: {
  icon: '' | 'info' | 'success' | 'error' | 'warning' | 'question',
  title: string,
  content: string|HTMLElement,
  header: string|HTMLElement,
  footer: string|HTMLElement,

  dataHolder: {},
 // ↓ if not footer ↓
  ok: string = 'OK',
  cancel: boolean|string = 'キャンセル',
  onOk: (dataHolder, e) => void,
  onCancel: (dataHolder, e) => void,
  onClose: (dataHolder, e) => void,
}
*/
function showDialog(options) {
  if (!dialogEl) {
    createDialogEl(options);
  } else {
    Object.assign(dialogEl, options);
  }
  dialogEl.open();
}

function createDialogEl({ ok, cancel, onOk, onCancel, onClose, ...options }) {
  if (!options.footer) {
    const divEl = document.createElement('div');
    divEl.style.textAlign = 'right';

    if (cancel !== false) {
      const cancelButton = new Kuc.Button({
        text: cancel || 'Cancel',
        type: 'normal'
      });
      cancelButton.style.paddingRight = '8px';
      cancelButton.addEventListener('click', (event) => {
        onCancel && onCancel(dialogEl.dataHolder, event);
        dialogEl.close();
      });
      divEl.appendChild(cancelButton);
    }

    const okButton = new Kuc.Button({
      text: ok || 'OK',
      type: 'submit'
    });
    okButton.addEventListener('click', (event) => {
      onOk && onOk(dialogEl.dataHolder, event);
      dialogEl.close();
    });
    divEl.appendChild(okButton);
    options.footer = divEl;
  }

  dialogEl = new Kuc.Dialog(options);
  if (onClose) {
    dialogEl.addEventListener('close', (event) => {
      onClose(dialogEl.dataHolder, event);
    });
  }
}

async function createExcelAndDownload({ bizLogic, api, excelName, exportName }) {
  const arrayBuffer = await getTemplateBuffer(api, excelName);
  if (!arrayBuffer) {
    // エラー
    return;
  }

  const workbook = new ExcelJS.Workbook();
  await workbook.xlsx.load(arrayBuffer);

  const worksheet = workbook.getWorksheet();
  try {
    await bizLogic(api, worksheet);
  } catch (e) {
    showError(true, '帳票出力エラー\n - ' + e);
    return;
  }
  const blob = await pvc.lib.exceljsUtil.saveWorkbookToBlob(workbook);
  saveAs(blob, exportName);
}

async function getTemplateBuffer(api, excelName) {
  try {
    const templateObj = await api.record.getAllRecordsWithId({
      app: env["Excelテンプレート"].appId,
      condition: `テンプレート名 = "${excelName}"`
    });
    const fileKey = templateObj[0]["テンプレートファイル"].value[0].fileKey;
    return await api.file.downloadFile({
      fileKey
    });
  } catch (e) {
    showError(true, '本アプリのExcelテンプレート読み取りエラー\n - ' + e);
  }
}

function findCellsInfo(worksheet, ids) {
  const result = ids.reduce((acc, key) => {
    acc[key] = [];
    return acc;
  }, {});

  let lastColVal;
  worksheet.eachRow((row, rowNumber) => {
    row.eachCell((cell, colNumber) => {
      const value = cell.value;
      if (value !== lastColVal && result[value]) {
        result[value].push({
          row: rowNumber,
          col: colNumber,
        });
      }
      lastColVal = value;
    });
  });

  return result;
}

function getLabelColsMapping(worksheet, row, fields) {
  const arr = worksheet.getRow(row).values;
  const changedIndices = [];
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] !== arr[i - 1]) {
      changedIndices.push({
        index: i,
        field: fields[changedIndices.length]
      });
    }
  }
  return changedIndices;
}

function createCopyFromTemplate(worksheet, { startPage,
  totalPages,
  copyPageRowStart,
  copyPageRowEnd,
  callback }) {

  const rowCount = copyPageRowEnd - copyPageRowStart + 1;
  let newPageRow = copyPageRowEnd + 1;

  for (let p = startPage; p <= totalPages; p++) {
    const copyRow = pvc.lib.exceljsUtil.copyRows(worksheet, copyPageRowStart, copyPageRowEnd);
    pvc.lib.exceljsUtil.insertRows(worksheet, newPageRow, copyRow);
    newPageRow += rowCount;
    callback(p, rowCount);
  }
}

function updateCell(worksheetOrRow, { base, left = 0, right = 0, up = 0, down = 0 }, data) {
  let cellObj;
  const row = base.row + (down - up);
  const col = base.col + (right - left);
  if (!worksheetOrRow._worksheet) {
    const worksheet = worksheetOrRow;
    cellObj = worksheet.getCell(row, col);
  } else {
    const rowObj = worksheetOrRow;
    cellObj = rowObj.getCell(col)
  }

  cellObj.value = data;
  if (!cellObj.alignment) {
    cellObj.alignment = {};
  }
  cellObj.alignment.wrapText = true;
}

function getMergedInfo(worksheet, { row, col }) {
  const key = columnToLetter(col) + row;
  return worksheet._merges[key];
}

function columnToLetter(columnIndex) {
  let letter = '';
  while (columnIndex > 0) {
    let remainder = (columnIndex - 1) % 26;
    letter = String.fromCharCode(65 + remainder) + letter;
    columnIndex = Math.floor((columnIndex - 1) / 26);
  }
  return letter;
}

function fillApproveArea(baseCells, worksheet, record) {
  const signLabels = ['園長', '主幹', '指導', '担任'];
  const signRow = baseCells['園長'][0].row + 1;
  for (let i = 0; i < signLabels.length; i++) {
    worksheet.getCell(signRow, baseCells['園長'][0].col + i).value = (record[signLabels[i]]?.value || '');
  }
}

function groupingBySex(list) {
  return list.reduce(([male, female], record) => {
    if (record['性別'].value === '男') {
      return [male.concat(record), female];
    } else if (record['性別'].value === '女') {
      return [male, female.concat(record)];
    }
    return [male, female];
  }, [[], []]);
}

const statusFieldMap = {
  '指導教諭確認中': '担任',
  '主幹確認中': '指導',
  '園長確認中': '主幹',
  '完了': '園長'
}

function addApproveFlowAction() {
  return kintone.events.on("app.record.detail.process.proceed", (event) => {
    const field = statusFieldMap[event.nextStatus.value];
    if (field) {
        event.record[field].value = kintone.getLoginUser().name;
    }
    return event;
});
}