import { getArweaveBalance, getArweaveWalletFromStoredDeviceKey } from '../services/arweave-wallet-service.js';
import {
  buildArweaveDataUrl,
  getArweaveUploadPrice,
  prepareAvatarImageFile,
  sha256HexFromArrayBuffer,
  uploadArweaveFile,
  validateArweaveTxId,
  validateSha256Hex,
  validateAvatarSourceFile,
} from '../services/arweave-file-service.js';
import { saveProfileAvatarArweave } from '../services/user-profile-params.js';

function escapeHtml(text) {
  return String(text || '')
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&#39;');
}

function formatBytes(bytes) {
  const value = Number(bytes || 0);
  if (!Number.isFinite(value) || value <= 0) return '0 B';
  if (value < 1024) return `${value} B`;
  if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
  return `${(value / (1024 * 1024)).toFixed(2)} MB`;
}

function formatAr(ar) {
  const n = Number(ar);
  if (!Number.isFinite(n)) return '0';
  return n.toLocaleString('ru-RU', { maximumFractionDigits: 6 });
}

function clearJwk(ctx) {
  if (!ctx?.jwk || typeof ctx.jwk !== 'object') return;
  Object.keys(ctx.jwk).forEach((key) => {
    ctx.jwk[key] = '';
  });
  ctx.jwk = null;
}

function setNodeText(node, text) {
  if (node) node.textContent = String(text || '');
}

export function openAvatarWizard({
  login,
  storagePwd,
  gateway,
  navigate,
  onAvatarSaved,
  onStatus,
} = {}) {
  const root = document.getElementById('modal-root');
  if (!root) return Promise.resolve(false);

  const cleanLogin = String(login || '').trim();
  const cleanStoragePwd = String(storagePwd || '').trim();
  const cleanGateway = String(gateway || '').trim();
  if (!cleanLogin || !cleanStoragePwd) {
    return Promise.reject(new Error('Нет активной сессии.'));
  }

  let closed = false;
  let lastPreviewUrl = '';
  let walletCtx = null;
  let balanceInfo = null;
  let optimized = null;
  let priceInfo = null;
  let uploadedTxId = '';
  let uploadedSha256Hex = '';

  function revokePreviewUrl() {
    if (!lastPreviewUrl) return;
    URL.revokeObjectURL(lastPreviewUrl);
    lastPreviewUrl = '';
  }

  function close(result = false, resolve) {
    if (closed) return;
    closed = true;
    revokePreviewUrl();
    clearJwk(walletCtx);
    walletCtx = null;
    root.innerHTML = '';
    resolve(result);
  }

  async function ensurePreviewImage(url, imageEl) {
    return new Promise((resolve, reject) => {
      const img = imageEl;
      img.onload = () => resolve(true);
      img.onerror = () => reject(new Error('Не удалось загрузить изображение по этому Transaction ID'));
      img.src = url;
    });
  }

  return new Promise((resolve) => {
    const showStepChoice = () => {
      if (closed) return;
      root.innerHTML = `
        <div class="modal" data-avatar-wizard-modal="true">
          <div class="modal-card stack avatar-wizard-card">
            <h3 class="modal-title">Сменить аватар</h3>
            <p class="meta-muted">Вы можете использовать уже загруженный файл Arweave или загрузить новый файл.</p>
            <div class="avatar-wizard-choice-grid">
              <button class="primary-btn" type="button" data-action="use-existing">Использовать существующий файл в Arweave</button>
              <button class="primary-btn" type="button" data-action="upload-new">Загрузить новый файл в Arweave</button>
              <button class="secondary-btn" type="button" data-action="cancel">Отмена</button>
            </div>
          </div>
        </div>
      `;
      const modal = root.querySelector('[data-avatar-wizard-modal="true"]');
      modal?.addEventListener('click', (event) => {
        if (event.target === modal) close(false, resolve);
      });
      root.querySelector('[data-action="cancel"]')?.addEventListener('click', () => close(false, resolve));
      root.querySelector('[data-action="use-existing"]')?.addEventListener('click', showStepExistingInput);
      root.querySelector('[data-action="upload-new"]')?.addEventListener('click', () => { void showStepUpload(); });
    };

    const showStepExistingInput = () => {
      if (closed) return;
      root.innerHTML = `
        <div class="modal" data-avatar-wizard-modal="true">
          <div class="modal-card stack avatar-wizard-card">
            <h3 class="modal-title">Использовать существующий файл в Arweave</h3>
            <label class="meta-muted" for="avatar-existing-txid">Transaction ID Arweave</label>
            <input class="input" id="avatar-existing-txid" type="text" maxlength="64" placeholder="Введите Transaction ID" />
            <p class="avatar-wizard-error" data-error="true"></p>
            <div class="avatar-wizard-actions">
              <button class="secondary-btn" type="button" data-action="back">Назад</button>
              <button class="primary-btn" type="button" data-action="next">Далее</button>
            </div>
          </div>
        </div>
      `;
      const modal = root.querySelector('[data-avatar-wizard-modal="true"]');
      const inputEl = root.querySelector('#avatar-existing-txid');
      const errorEl = root.querySelector('[data-error="true"]');
      modal?.addEventListener('click', (event) => {
        if (event.target === modal) close(false, resolve);
      });
      root.querySelector('[data-action="back"]')?.addEventListener('click', showStepChoice);
      root.querySelector('[data-action="next"]')?.addEventListener('click', () => {
        const txId = String(inputEl?.value || '').trim();
        if (!validateArweaveTxId(txId)) {
          setNodeText(errorEl, 'Некорректный Transaction ID Arweave.');
          return;
        }
        setNodeText(errorEl, '');
        void showStepExistingPreview(txId);
      });
      window.setTimeout(() => inputEl?.focus(), 0);
    };

    const showStepExistingPreview = async (txId) => {
      if (closed) return;
      const previewUrl = buildArweaveDataUrl({ gateway: cleanGateway, txId });
      let existingSha256Hex = '';
      root.innerHTML = `
        <div class="modal" data-avatar-wizard-modal="true">
          <div class="modal-card stack avatar-wizard-card">
            <h3 class="modal-title">Предпросмотр аватара</h3>
            <div class="avatar-preview-circle avatar-wizard-preview">
              <img alt="Предпросмотр аватара" data-preview-image="true" />
            </div>
            <p class="meta-muted">После сохранения в профиль будут записаны SHA-256 и Transaction ID. Сам файл хранится в Arweave.</p>
            <p class="avatar-wizard-error" data-error="true"></p>
            <div class="avatar-wizard-actions">
              <button class="secondary-btn" type="button" data-action="back">Назад</button>
              <button class="primary-btn" type="button" data-action="save">Сохранить аватар</button>
            </div>
          </div>
        </div>
      `;
      const modal = root.querySelector('[data-avatar-wizard-modal="true"]');
      const imageEl = root.querySelector('[data-preview-image="true"]');
      const errorEl = root.querySelector('[data-error="true"]');
      const saveBtn = root.querySelector('[data-action="save"]');
      modal?.addEventListener('click', (event) => {
        if (event.target === modal) close(false, resolve);
      });
      root.querySelector('[data-action="back"]')?.addEventListener('click', showStepExistingInput);
      if (saveBtn instanceof HTMLButtonElement) saveBtn.disabled = true;

      try {
        await ensurePreviewImage(previewUrl, imageEl);
        const response = await fetch(previewUrl, { method: 'GET', cache: 'no-store' });
        if (!response.ok) throw new Error('BAD_AVATAR_FETCH');
        existingSha256Hex = await sha256HexFromArrayBuffer(await response.arrayBuffer());
        if (!validateSha256Hex(existingSha256Hex)) throw new Error('BAD_AVATAR_HASH');
        if (saveBtn instanceof HTMLButtonElement) saveBtn.disabled = false;
      } catch (error) {
        setNodeText(errorEl, 'Не удалось проверить файл по этому Transaction ID.');
        if (saveBtn instanceof HTMLButtonElement) saveBtn.disabled = true;
      }

      saveBtn?.addEventListener('click', async () => {
        try {
          await saveProfileAvatarArweave(cleanLogin, txId, existingSha256Hex);
          if (typeof onAvatarSaved === 'function') await onAvatarSaved();
          close(true, resolve);
        } catch {
          setNodeText(errorEl, 'Не удалось сохранить аватар в профиль.');
        }
      });
    };

    const showStepZeroBalance = () => {
      if (closed) return;
      root.innerHTML = `
        <div class="modal" data-avatar-wizard-modal="true">
          <div class="modal-card stack avatar-wizard-card">
            <h3 class="modal-title">Недостаточно средств</h3>
            <p class="meta-muted">У вас нулевой баланс Arweave. Для загрузки аватара нужен AR.</p>
            <div class="avatar-wizard-actions">
              <button class="primary-btn" type="button" data-action="to-wallet">Перейти в кошелёк</button>
              <button class="secondary-btn" type="button" data-action="cancel">Отмена</button>
            </div>
          </div>
        </div>
      `;
      root.querySelector('[data-action="to-wallet"]')?.addEventListener('click', () => {
        close(false, resolve);
        if (typeof navigate === 'function') navigate('wallet-view');
      });
      root.querySelector('[data-action="cancel"]')?.addEventListener('click', () => close(false, resolve));
    };

    const showStepUploadForm = () => {
      if (closed) return;
      root.innerHTML = `
        <div class="modal" data-avatar-wizard-modal="true">
          <div class="modal-card stack avatar-wizard-card">
            <h3 class="modal-title">Загрузить новый файл в Arweave</h3>
            <p class="meta-muted">Баланс: ${formatAr(balanceInfo?.ar)} AR</p>
            <label class="meta-muted" for="avatar-file-input">Выберите изображение</label>
            <input class="input" id="avatar-file-input" type="file" accept="image/jpeg,image/png,image/webp" />
            <p class="meta-muted">Поддерживаются JPEG, PNG, WebP. Максимальный исходный файл — 10 MB. Перед загрузкой изображение будет уменьшено для аватарки.</p>
            <div class="avatar-preview-circle avatar-wizard-preview" hidden data-preview-wrap="true">
              <img alt="Предпросмотр аватара" data-preview-image="true" />
            </div>
            <div class="avatar-wizard-meta" data-meta="true"></div>
            <p class="meta-muted">После сохранения в профиль будут записаны SHA-256 и Transaction ID. Сам файл хранится в Arweave.</p>
            <p class="avatar-wizard-error" data-error="true"></p>
            <div class="avatar-wizard-actions">
              <button class="secondary-btn" type="button" data-action="back">Назад</button>
              <button class="primary-btn" type="button" data-action="upload" disabled>Загрузить в Arweave</button>
            </div>
          </div>
        </div>
      `;

      const modal = root.querySelector('[data-avatar-wizard-modal="true"]');
      const fileInput = root.querySelector('#avatar-file-input');
      const errorEl = root.querySelector('[data-error="true"]');
      const metaEl = root.querySelector('[data-meta="true"]');
      const previewWrap = root.querySelector('[data-preview-wrap="true"]');
      const previewImage = root.querySelector('[data-preview-image="true"]');
      const uploadBtn = root.querySelector('[data-action="upload"]');

      let selectedFile = null;
      optimized = null;
      priceInfo = null;
      uploadedSha256Hex = '';

      modal?.addEventListener('click', (event) => {
        if (event.target === modal) close(false, resolve);
      });
      root.querySelector('[data-action="back"]')?.addEventListener('click', showStepChoice);

      fileInput?.addEventListener('change', async () => {
        setNodeText(errorEl, '');
        setNodeText(metaEl, '');
        uploadBtn.disabled = true;
        revokePreviewUrl();

        selectedFile = fileInput.files?.[0] || null;
        if (!selectedFile) {
          setNodeText(errorEl, 'Выберите файл изображения.');
          return;
        }

        try {
          validateAvatarSourceFile(selectedFile);
          optimized = await prepareAvatarImageFile(selectedFile);
          priceInfo = await getArweaveUploadPrice({
            gateway: cleanGateway,
            byteLength: optimized.file.size,
          });

          lastPreviewUrl = URL.createObjectURL(optimized.file);
          previewImage.src = lastPreviewUrl;
          previewWrap.hidden = false;

          const hasFunds = BigInt(balanceInfo.winston) >= BigInt(priceInfo.winston);
          metaEl.innerHTML = `
            <div>Исходный размер: ${escapeHtml(formatBytes(optimized.originalSizeBytes))}</div>
            <div>Итоговый размер: ${escapeHtml(formatBytes(optimized.optimizedSizeBytes))}</div>
            <div>Итоговое разрешение: ${escapeHtml(`${optimized.width} × ${optimized.height}`)}</div>
            <div>Тип файла: ${escapeHtml(optimized.contentType)}</div>
            <div>SHA-256: ${escapeHtml(String(optimized.sha256Hex || '').toLowerCase())}</div>
            <div>Примерная цена загрузки: ${escapeHtml(formatAr(priceInfo.ar))} AR</div>
          `;

          if (!hasFunds) {
            setNodeText(errorEl, 'Недостаточно средств для загрузки.');
            uploadBtn.disabled = true;
            return;
          }
          uploadBtn.disabled = false;
        } catch (error) {
          const message = String(error?.message || '');
          if (message === 'Выберите файл изображения.' || message === 'Поддерживаются только JPEG, PNG или WebP.' || message === 'Файл слишком большой. Максимум 10 MB.') {
            setNodeText(errorEl, message);
          } else if (message.includes('цену загрузки')) {
            setNodeText(errorEl, 'Не удалось получить баланс Arweave.');
          } else {
            setNodeText(errorEl, 'Не удалось подготовить изображение.');
          }
        }
      });

      uploadBtn?.addEventListener('click', async () => {
        setNodeText(errorEl, '');
        if (!optimized?.file) {
          setNodeText(errorEl, 'Выберите файл изображения.');
          return;
        }
        if (!priceInfo || BigInt(balanceInfo.winston) < BigInt(priceInfo.winston)) {
          setNodeText(errorEl, 'Недостаточно средств для загрузки.');
          return;
        }

        uploadBtn.disabled = true;
        try {
          const uploaded = await uploadArweaveFile({
            gateway: cleanGateway,
            jwk: walletCtx?.jwk,
            file: optimized.file,
            tags: [
              { name: 'SHiNE-Profile-Login', value: cleanLogin },
            ],
          });
          uploadedTxId = String(uploaded.id || '').trim();
          uploadedSha256Hex = String(optimized?.sha256Hex || '').trim().toLowerCase();
          if (!uploadedTxId) {
            throw new Error('Пустой Transaction ID');
          }
          if (!validateSha256Hex(uploadedSha256Hex)) {
            throw new Error('Некорректный SHA256');
          }
          showStepUploaded();
        } catch {
          setNodeText(errorEl, 'Не удалось загрузить файл в Arweave.');
          uploadBtn.disabled = false;
        }
      });
    };

    const showStepUploaded = () => {
      if (closed) return;
      root.innerHTML = `
        <div class="modal" data-avatar-wizard-modal="true">
          <div class="modal-card stack avatar-wizard-card">
            <h3 class="modal-title">Файл загружен в Arweave</h3>
            <p class="meta-muted">Transaction ID:</p>
            <p class="avatar-wizard-meta">${escapeHtml(uploadedTxId)}</p>
            <p class="meta-muted">SHA-256:</p>
            <p class="avatar-wizard-meta">${escapeHtml(uploadedSha256Hex)}</p>
            <p class="avatar-wizard-error" data-error="true"></p>
            <div class="avatar-wizard-actions">
              <button class="ghost-btn" type="button" data-action="copy-id">Скопировать ID</button>
              <button class="primary-btn" type="button" data-action="set-avatar">Сделать аватаром</button>
            </div>
            <button class="secondary-btn" type="button" data-action="close">Закрыть</button>
          </div>
        </div>
      `;

      const errorEl = root.querySelector('[data-error="true"]');
      root.querySelector('[data-action="copy-id"]')?.addEventListener('click', async () => {
        try {
          await navigator.clipboard.writeText(uploadedTxId);
          setNodeText(errorEl, '');
        } catch {
          setNodeText(errorEl, 'Не удалось скопировать Transaction ID.');
        }
      });
      root.querySelector('[data-action="set-avatar"]')?.addEventListener('click', async () => {
        try {
          await saveProfileAvatarArweave(cleanLogin, uploadedTxId, uploadedSha256Hex);
          if (typeof onAvatarSaved === 'function') await onAvatarSaved();
          close(true, resolve);
        } catch {
          setNodeText(errorEl, 'Не удалось сохранить аватар в профиль.');
        }
      });
      root.querySelector('[data-action="close"]')?.addEventListener('click', () => close(false, resolve));
    };

    const showStepUpload = async () => {
      if (closed) return;
      root.innerHTML = `
        <div class="modal" data-avatar-wizard-modal="true">
          <div class="modal-card stack avatar-wizard-card">
            <h3 class="modal-title">Подготовка загрузки</h3>
            <p class="meta-muted" data-loading="true">Загружаем Arweave-кошелёк...</p>
            <p class="avatar-wizard-error" data-error="true"></p>
            <div class="avatar-wizard-actions">
              <button class="secondary-btn" type="button" data-action="back">Назад</button>
            </div>
          </div>
        </div>
      `;

      const loadingEl = root.querySelector('[data-loading="true"]');
      const errorEl = root.querySelector('[data-error="true"]');
      root.querySelector('[data-action="back"]')?.addEventListener('click', showStepChoice);
      try {
        walletCtx = await getArweaveWalletFromStoredDeviceKey({
          login: cleanLogin,
          storagePwd: cleanStoragePwd,
          onStatus: (message) => {
            setNodeText(loadingEl, message);
            if (typeof onStatus === 'function') onStatus(message);
          },
        });
        balanceInfo = await getArweaveBalance({
          gateway: cleanGateway,
          address: walletCtx.address,
        });
      } catch (error) {
        setNodeText(errorEl, 'Не удалось получить баланс Arweave.');
        return;
      }

      if (BigInt(balanceInfo.winston) <= 0n) {
        showStepZeroBalance();
        return;
      }
      showStepUploadForm();
    };

    showStepChoice();
  });
}
