<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Edytor Zdjęć Produktowych</title>

  <style>
    /* --- GŁÓWNE STYLE --- */
    body { font-family: sans-serif; padding: 20px; color: #333; }
    h2 { margin-bottom: 20px; }

    /* --- WRAPPER CROPPERA --- */
    .cropper-wrapper {
      position: relative;
      width: 100%;
      height: 500px;
      background: #222;
      margin-bottom: 15px;
      border-radius: 8px;
      overflow: hidden;
      display: none; /* Ukryty domyślnie */
      user-select: none;
      touch-action: none;
    }

    cropper-canvas { width: 100%; height: 100%; }

    /* Stała ramka wyboru */
    cropper-selection {
      outline: 2px solid #e74c3c !important; /* Czerwona ramka */
      pointer-events: none;
    }

    /* --- OVERLAY I UCHWYTY (HANDLES) --- */
    .photo-handles {
      position: absolute;
      inset: 0;
      pointer-events: none; /* Kluczowe: przepuszcza kliki do obrazka */
      z-index: 20;
    }

    .photo-outline {
      position: absolute;
      inset: 6px;
      border: 2px dashed rgba(255, 255, 255, 0.6);
      border-radius: 6px;
    }

    .handle {
      position: absolute;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background: #fff;
      border: 2px solid #007bff;
      box-shadow: 0 2px 5px rgba(0,0,0,0.4);
      pointer-events: auto; /* Tylko kropki są klikalne */
      transition: transform 0.1s;
    }
    .handle:active { transform: scale(1.2); }

    /* Pozycje uchwytów */
    .handle.tl { left: 10px; top: 10px; cursor: nwse-resize; }
    .handle.tr { right: 10px; top: 10px; cursor: nesw-resize; }
    .handle.bl { left: 10px; bottom: 10px; cursor: nesw-resize; }
    .handle.br { right: 10px; bottom: 10px; cursor: nwse-resize; }

    /* --- PASEK NARZĘDZI --- */
    #toolbar {
      display: none;
      gap: 10px;
      align-items: center;
      flex-wrap: wrap;
      margin-bottom: 20px;
    }
    #toolbar.show { display: flex; }

    .btn {
      padding: 8px 16px;
      background-color: #007bff;
      color: white;
      border: none;
      cursor: pointer;
      font-size: 15px;
      border-radius: 6px;
      transition: background 0.2s;
    }
    .btn:hover { background-color: #0056b3; }
    .btn:disabled { background-color: #ccc; cursor: not-allowed; }

    .chip {
      padding: 6px 12px;
      border: 1px solid #ccc;
      border-radius: 20px;
      font-size: 13px;
      background: #f8f9fa;
      font-weight: 600;
    }
    
    #hint { font-size: 13px; color: #666; margin-left: auto; }
  </style>
</head>

<body>

  <h2>Przesyłanie zdjęcia produktu</h2>

  <div style="margin-bottom: 20px;">
    <label class="btn" for="inputImage">📂 Wybierz zdjęcie</label>
    <input type="file" id="inputImage" accept="image/*" style="display:none" />
    <span id="fileName" style="margin-left: 10px; color:#555;"></span>
  </div>

  <div class="cropper-wrapper" id="cropperWrapper">
    <cropper-canvas id="my-cropper" background>
      <cropper-image 
        id="cropperImage" 
        initial-center-size="cover" 
        translatable 
        scalable
      ></cropper-image>
      
      <cropper-handle action="move" plain></cropper-handle>

      <cropper-selection id="cropperSelection" initial-coverage="0.6"></cropper-selection>
    </cropper-canvas>

    <div class="photo-handles" id="photoHandles">
      <div class="photo-outline"></div>
      <div class="handle tl" data-pos="top" title="Zmień rozmiar"></div>
      <div class="handle tr" data-pos="top" title="Zmień rozmiar"></div>
      <div class="handle bl" data-pos="bottom" title="Zmień rozmiar"></div>
      <div class="handle br" data-pos="bottom" title="Zmień rozmiar"></div>
    </div>
  </div>

  <div id="toolbar">
    <button type="button" class="btn" id="btnZoomIn">+</button>
    <button type="button" class="btn" id="btnZoomOut">-</button>
    <button type="button" class="btn" id="btnReset">Reset</button>
    <span class="chip" id="formatInfo"></span>
    <span id="hint">Mysz/Dotyk: Przesuń | Kółko/Rogi: Zoom</span>
  </div>

  <button id="btnUpload" class="btn" style="display:none; width: 100%; padding: 12px;">Przytnij i Zapisz</button>
  <div id="result" style="margin-top: 20px;"></div>

  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="https://unpkg.com/cropperjs@2.1.0/dist/cropper.js"></script>

  <script>
    /**
     * KONFIGURACJA
     * Wszystkie stałe w jednym miejscu dla łatwej edycji.
     */
    const CONFIG = {
      dims: {
        adminW: 8,    // cm
        adminH: 12,   // cm
        outputW: 800, // px
        outputH: 1200 // px
      },
      zoomSensitivity: 0.004,
      selectors: {
        input: '#inputImage',
        fileName: '#fileName',
        wrapper: '#cropperWrapper',
        uploadBtn: '#btnUpload',
        toolbar: '#toolbar',
        result: '#result',
        cropperCanvas: 'my-cropper',
        cropperImage: 'cropperImage',
        cropperSelection: 'cropperSelection',
        handles: '.handle'
      }
    };

    /**
     * STATE
     * Przechowywanie stanu aplikacji
     */
    const State = {
      isResizing: false,
      startY: 0,
      isInverted: false // Czy używamy dolnych uchwytów (odwrócona logika)
    };

    /**
     * DOM MANAGER
     * Cache'owanie elementów jQuery i JS
     */
    const DOM = {
      $input: $(CONFIG.selectors.input),
      $name: $(CONFIG.selectors.fileName),
      $wrapper: $(CONFIG.selectors.wrapper),
      $uploadBtn: $(CONFIG.selectors.uploadBtn),
      $toolbar: $(CONFIG.selectors.toolbar),
      $result: $(CONFIG.selectors.result),
      elCanvas: document.getElementById(CONFIG.selectors.cropperCanvas),
      elImage: document.getElementById(CONFIG.selectors.cropperImage),
      elSelection: document.getElementById(CONFIG.selectors.cropperSelection),
      elsHandles: document.querySelectorAll(CONFIG.selectors.handles)
    };

    /**
     * GŁÓWNY KONTROLER APLIKACJI
     */
    const App = {
      init() {
        this.renderInfo();
        this.bindGlobalEvents();
        this.bindZoomHandlers();
      },

      // Wyświetlenie formatu na toolbarze
      renderInfo() {
        const { adminW, adminH } = CONFIG.dims;
        $('#formatInfo').text(`Format: ${adminW}×${adminH} cm`);
      },

      // Obliczanie i centrowanie ramki wyboru
      centerSelection() {
        const { adminW, adminH } = CONFIG.dims;
        const ratio = adminW / adminH;
        
        DOM.elSelection.aspectRatio = ratio;

        const rect = DOM.elCanvas.getBoundingClientRect();
        if (!rect.width || !rect.height) return;

        // Maksymalnie 70% obszaru
        const maxW = rect.width * 0.7;
        const maxH = rect.height * 0.7;

        let selW, selH;
        
        // Dopasowanie do węższego wymiaru
        if (maxW / maxH > ratio) {
          selH = maxH;
          selW = selH * ratio;
        } else {
          selW = maxW;
          selH = selW / ratio;
        }

        const x = (rect.width - selW) / 2;
        const y = (rect.height - selH) / 2;

        DOM.elSelection.$change(x, y, selW, selH, ratio);
      },

      // Obsługa zdarzeń globalnych (pliki, przyciski)
      bindGlobalEvents() {
        // 1. Wczytanie pliku
        DOM.$input.on('change', function() {
          const [file] = this.files;
          if (!file) return;

          if (!/^image\/\w+$/.test(file.type)) {
            alert("To nie jest plik graficzny!");
            return;
          }

          DOM.$name.text(file.name);
          DOM.elImage.src = URL.createObjectURL(file);

          // Pokaż UI
          DOM.$wrapper.fadeIn();
          DOM.$uploadBtn.fadeIn();
          DOM.$toolbar.addClass('show');

          // Inicjalizacja croppera
          DOM.elImage.$ready(() => {
            DOM.elImage.$center('cover');
            App.centerSelection();
          });
        });

        // 2. Toolbar - Przyciski
        $('#btnZoomIn').on('click', () => DOM.elImage.$zoom(0.1));
        $('#btnZoomOut').on('click', () => DOM.elImage.$zoom(-0.1));
        $('#btnReset').on('click', () => DOM.elImage.$center('cover'));

        // 3. Zoom kółkiem myszy
        DOM.$wrapper.on('wheel', (e) => {
          e.preventDefault();
          const delta = e.originalEvent.deltaY;
          DOM.elImage.$zoom(delta < 0 ? 0.08 : -0.08);
        });

        // 4. Resize okna przeglądarki
        window.addEventListener('resize', () => {
          if (DOM.$wrapper.is(':visible')) App.centerSelection();
        });

        // 5. Upload (Zapisz)
        DOM.$uploadBtn.on('click', this.handleUpload);
      },

      // Logika "Ciągnij za rogi by zmienić zoom"
      bindZoomHandlers() {
        const onPointerDown = (e) => {
          State.isResizing = true;
          State.startY = e.clientY;
          // Sprawdzamy czy to dolny uchwyt (bl, br) używając dataset lub klasy
          State.isInverted = e.target.dataset.pos === 'bottom';

          e.preventDefault();
          e.stopPropagation();

          document.addEventListener('pointermove', onPointerMove, { passive: false });
          document.addEventListener('pointerup', onPointerUp, { passive: false, once: true });
        };

        const onPointerMove = (e) => {
          if (!State.isResizing) return;

          let dy = e.clientY - State.startY;
          State.startY = e.clientY;

          // Jeśli dolny uchwyt -> odwracamy znak
          if (State.isInverted) dy = -dy;

          // Oblicz zoom
          const step = (-dy) * CONFIG.zoomSensitivity;
          if (step !== 0) DOM.elImage.$zoom(step);

          e.preventDefault();
        };

        const onPointerUp = () => {
          State.isResizing = false;
          document.removeEventListener('pointermove', onPointerMove);
        };

        // Podpięcie pod wszystkie uchwyty
        DOM.elsHandles.forEach(el => {
          el.addEventListener('pointerdown', onPointerDown, { passive: false });
        });
      },

      // Logika wysyłki na serwer
      handleUpload() {
        const btn = $(this);
        btn.prop('disabled', true).text('Przetwarzanie...');

        const { outputW, outputH, adminW, adminH } = CONFIG.dims;

        // Generowanie canvasu
        DOM.elSelection.$toCanvas({ width: outputW, height: outputH })
          .then(canvas => {
            canvas.toBlob(blob => {
              const formData = new FormData();
              
              // Destrukturyzacja do dodania danych
              formData.append("original_image", DOM.$input[0].files[0]);
              formData.append("cropped_image", blob, "cropped.jpg");
              
              // Metadane
              const meta = { product_id: 123, admin_w_cm: adminW, admin_h_cm: adminH, out_w_px: outputW, out_h_px: outputH };
              Object.entries(meta).forEach(([key, val]) => formData.append(key, val));

              // AJAX
              $.ajax({
                url: "product-img-save.php",
                method: "POST",
                data: formData,
                processData: false,
                contentType: false,
                success: (resp) => {
                  DOM.$result.html(resp);
                  App.resetUI();
                },
                error: () => {
                  alert("Błąd zapisu!");
                  btn.prop('disabled', false).text('Przytnij i Zapisz');
                }
              });
            }, "image/jpeg", 0.92);
          })
          .catch(() => {
            alert("Błąd generowania obrazu.");
            btn.prop('disabled', false).text('Przytnij i Zapisz');
          });
      },

      // Reset po udanym wgraniu
      resetUI() {
        DOM.$wrapper.hide();
        DOM.$toolbar.removeClass('show');
        DOM.$uploadBtn.hide().prop('disabled', false).text('Przytnij i Zapisz');
        DOM.$input.val('');
        DOM.$name.text('');
      }
    };

    // START
    $(document).ready(() => App.init());
  </script>
</body>
</html>