(function (root, factory) {
  const createSearchReplyDraftStore = factory();
  if (typeof module === 'object' && module.exports) module.exports = createSearchReplyDraftStore;
  else root.createSearchReplyDraftStore = createSearchReplyDraftStore;
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
  'use strict';

  const dbName = 'stackchain-search-reply-drafts-v1';
  const storeName = 'drafts';

  function requestResult(request) {
    return new Promise((resolve, reject) => {
      request.onsuccess = () => resolve(request.result ?? null);
      request.onerror = () => reject(request.error || new Error('Search reply draft storage failed.'));
    });
  }

  function createTransaction(indexedDB) {
    if (!indexedDB) return null;
    let databasePromise;
    function database() {
      if (!databasePromise) databasePromise = new Promise((resolve, reject) => {
        const request = indexedDB.open(dbName, 1);
        request.onupgradeneeded = () => {
          if (!request.result.objectStoreNames.contains(storeName)) {
            request.result.createObjectStore(storeName, { keyPath:'id' });
          }
        };
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error || new Error('Search reply draft storage is unavailable.'));
      });
      return databasePromise;
    }
    return async (operation, key, value) => {
      const db = await database();
      const transaction = db.transaction(storeName, operation === 'get' ? 'readonly' : 'readwrite');
      const records = transaction.objectStore(storeName);
      if (operation === 'put') return requestResult(records.put(value));
      if (operation === 'delete') return requestResult(records.delete(key));
      return requestResult(records.get(key));
    };
  }

  function normalizedTarget(target) {
    const kind = String(target?.kind || '');
    const repository = String(target?.repository || '');
    const number = Number(target?.number || 0);
    if (!['issue', 'pull'].includes(kind) || !repository || !Number.isInteger(number) || number < 1) {
      throw new Error('Choose a Search result before saving photo evidence.');
    }
    return { kind, repository, number };
  }

  function attachment(value) {
    const blob = value?.blob;
    const data = String(value?.data || '');
    if (!blob && !data) throw new Error('A saved Search photo is unavailable.');
    const note = String(value?.note || '').replace(/\s+/g, ' ').trim().slice(0, 240);
    const operationId = String(value?.operationId || '').slice(0, 128);
    const markdown = String(value?.confirmed?.markdown || '');
    return {
      filename:String(value?.filename || ''),
      contentType:String(value?.contentType || ''),
      ...(blob ? { blob } : { data }),
      ...(note ? { note } : {}),
      ...(operationId ? { operationId } : {}),
      ...(markdown ? { confirmed:{ markdown } } : {}),
    };
  }

  return function createSearchReplyDraftStore({
    indexedDB = globalThis.indexedDB,
    transaction,
    getOwnerLogin = () => '',
  } = {}) {
    const transact = transaction || createTransaction(indexedDB);

    function identity(target) {
      const ownerLogin = String(getOwnerLogin() || '').trim();
      if (!ownerLogin) throw new Error('Confirm your Gitea account before saving Search photos.');
      const normalized = normalizedTarget(target);
      return {
        ownerLogin,
        target:normalized,
        id:[ownerLogin, normalized.kind, normalized.repository, normalized.number]
          .map(value => encodeURIComponent(String(value))).join(':'),
      };
    }

    async function save(target, values) {
      if (!transact) throw new Error('Photo draft storage needs IndexedDB. Your current photos are still here.');
      const { id, ownerLogin, target:normalized } = identity(target);
      const list = (Array.isArray(values) ? values : [values]).filter(Boolean).slice(0, 5).map(attachment);
      if (!list.length) {
        await transact('delete', id);
        return null;
      }
      await transact('put', id, { id, version:1, ownerLogin, ...normalized, attachments:list });
      return list;
    }

    async function load(target) {
      if (!transact) return null;
      const { id, ownerLogin, target:normalized } = identity(target);
      const record = await transact('get', id);
      if (record?.version !== 1 || record.ownerLogin !== ownerLogin || record.kind !== normalized.kind ||
          record.repository !== normalized.repository || Number(record.number) !== normalized.number ||
          !Array.isArray(record.attachments) || !record.attachments.length) return null;
      return record.attachments.slice(0, 5).map(attachment);
    }

    async function remove(target) {
      if (!transact) return false;
      const { id } = identity(target);
      await transact('delete', id);
      return true;
    }

    return { save, load, remove };
  };
});
