---
const configuredApiBase = import.meta.env.PUBLIC_PPR_API_BASE ?? 'https://ppr.swansea-airport.wales/api/v1';
const pprApiBase = configuredApiBase.replace(/\/$/, '');
const droneRequestEndpoint = `${pprApiBase}/drone-requests/public`;
const frzGeoJsonEndpoint = `${pprApiBase}/drone-requests/frz`;
---

<section class="drone-shell surface" aria-labelledby="drone-heading">
  <div class="drone-head">
    <p class="eyebrow">Drone flight request</p>
    <h2 id="drone-heading" class="section-title">Request a flight within the FRZ</h2>
    <p class="section-copy">
      Tell us when and where you plan to fly. Pick the operating location on the map or enter it
      manually, then click Submit. We will review your request and contact you if we need any further information.
    </p>
    <p>
      If your flight is outside the FRZ, you do not need to submit a request, but it would still be appreciated if it is in the vicinity. Please follow the <a href="/about/drones/">local drone guidance</a> and fly safely.
    </p>
  </div>

  

  <form id="drone-form" class="drone-form">
    <div class="drone-grid">
            <div class="drone-field">
        <label for="operator-name">Operator Name <span aria-hidden="true">*</span></label>
        <input type="text" id="operator-name" name="operator_name" autocomplete="organization" required />
      </div>

      <div class="drone-field">
        <label for="operator-id">Operator ID <span aria-hidden="true">*</span></label>
        <input type="text" id="operator-id" name="operator_id" autocomplete="off" autocapitalize="characters" class="uppercase-input" required />
      </div>

        <div class="drone-field">
        <label for="flyer-name">Flyer Name <span aria-hidden="true">*</span></label>
        <input type="text" id="flyer-name" name="flyer_name" autocomplete="name" required />
      </div>

      <div class="drone-field">
        <label for="flyer-id">Flyer ID <span aria-hidden="true">*</span></label>
        <input type="text" id="flyer-id" name="flyer_id" autocomplete="off" autocapitalize="characters" class="uppercase-input" required />
      </div>

      <div class="drone-field">
        <label for="flight-date">Date of Flight <span aria-hidden="true">*</span></label>
        <input type="date" id="flight-date" name="flight_date" required />
      </div>

      <div class="drone-field">
        <label for="takeoff-time">Estimated Take Off Time <span aria-hidden="true">*</span></label>
        <select id="takeoff-time" name="estimated_takeoff_time" required>
          <option value="">Select Time</option>
        </select>
      </div>

      <div class="drone-field">
        <label for="completion-time">Estimated Completion Time <span aria-hidden="true">*</span></label>
        <select id="completion-time" name="estimated_completion_time" required>
          <option value="">Select Time</option>
        </select>
      </div>

      <div class="drone-field">
        <label for="max-elevation">Maximum Elevation, feet AMSL <span aria-hidden="true">*</span></label>
        <input type="number" id="max-elevation" name="maximum_elevation_ft_amsl" min="0" step="1" inputmode="numeric" required />
      </div>

      <div class="drone-field drone-full">
        <label for="location-description">Location <span aria-hidden="true">*</span></label>
        <input
          type="text"
          id="location-description"
          name="location_description"
          placeholder="Site name, address, grid reference, or map-selected coordinates"
          autocomplete="off"
          required
        />
      </div>

      <div class="drone-map-panel drone-full">
        <div class="drone-map-toolbar">
          <div>
            <p class="drone-map-title">Operating Location</p>
            <p id="map-status" class="drone-map-status">Click the map to drop the requested flight location.</p>
          </div>
          <button type="button" class="button secondary" id="clear-location">Clear Location</button>
        </div>
        <div id="drone-map" class="drone-map" aria-label="Clickable map for selecting drone operating location"></div>
        <div class="drone-field drone-map-location">
          <label for="map-location-summary">Selected Map Coordinates</label>
          <input
            type="text"
            id="map-location-summary"
            placeholder="No map location selected"
            readonly
          />
        </div>
        <div class="drone-map-legend" aria-label="Map overlay legend">
          <span><i class="legend-swatch frz"></i>Flight restriction zone</span>
          <span><i class="legend-swatch selected"></i>Selected location</span>
        </div>
        <input type="hidden" id="location-lat" name="location_latitude" />
        <input type="hidden" id="location-lng" name="location_longitude" />
        <input type="hidden" id="location-inside-frz" name="location_inside_frz" />
      </div>

      <div class="drone-field">
        <label for="email">Email Address <span aria-hidden="true">*</span></label>
        <input type="email" id="email" name="email" autocomplete="email" required />
      </div>

      <div class="drone-field">
        <label for="phone">Phone Number <span aria-hidden="true">*</span></label>
        <input type="tel" id="phone" name="phone" autocomplete="tel" required />
      </div>

      <div class="drone-field drone-full">
        <label for="notes">Operational Notes</label>
        <textarea id="notes" name="notes" rows="4" placeholder="Purpose of flight, aircraft type, contact on site, or other useful details..."></textarea>
      </div>
    </div>

    <div class="drone-actions">
      <button type="submit" class="button primary" id="submit-btn">Submit Drone Request</button>
    </div>
  </form>

  <div class="drone-loading" id="loading" role="status" aria-live="polite">
    <span class="drone-spinner" aria-hidden="true"></span>
    Submitting your drone request...
  </div>

  <div class="drone-success notice" id="success-message" role="status" aria-live="polite" tabindex="-1">
    <h3>Drone Request Submitted.</h3>
    <p>Your drone request has been submitted. We will review it and contact you if we need any further information.</p>
    <p class="drone-reference" id="reference-number-message" hidden>
      Reference number: <strong id="reference-number"></strong> - please make a note of this in case you don't get the email.
    </p>
  </div>
</section>

<div id="notification" class="drone-notification" role="status" aria-live="polite"></div>

<script define:vars={{ droneRequestEndpoint, frzGeoJsonEndpoint }}>
  (() => {
    const DRONE_REQUEST_ENDPOINT = droneRequestEndpoint;
    const FRZ_GEOJSON_ENDPOINT = frzGeoJsonEndpoint;
    const LEAFLET_CSS = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';
    const LEAFLET_JS = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';
    const ARP = { lat: 51.6053, lng: -4.0678 };

    let map;
    let selectedMarker;
    let frzGeoJson;

    const get = (id) => document.getElementById(id);

    function loadStylesheet(href) {
      if (document.querySelector(`link[href="${href}"]`)) return;
      const link = document.createElement('link');
      link.rel = 'stylesheet';
      link.href = href;
      document.head.append(link);
    }

    function loadScript(src) {
      return new Promise((resolve, reject) => {
        if (window.L) {
          resolve();
          return;
        }

        const existingScript = document.querySelector(`script[src="${src}"]`);
        if (existingScript) {
          existingScript.addEventListener('load', resolve, { once: true });
          existingScript.addEventListener('error', reject, { once: true });
          return;
        }

        const script = document.createElement('script');
        script.src = src;
        script.async = true;
        script.onload = resolve;
        script.onerror = reject;
        document.head.append(script);
      });
    }

    function initializeTimeDropdowns() {
      ['takeoff-time', 'completion-time'].forEach((selectId) => {
        const select = get(selectId);
        select.replaceChildren(new Option('Select Time', ''));

        for (let hour = 0; hour < 24; hour += 1) {
          for (let minute = 0; minute < 60; minute += 15) {
            const value = `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
            select.append(new Option(value, value));
          }
        }
      });
    }

    function formatDate(date) {
      return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
    }

    function formatTime(date) {
      return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
    }

    function setDefaultDateTime() {
      const takeoff = new Date();
      takeoff.setHours(takeoff.getHours() + 1, 0, 0, 0);

      const completion = new Date(takeoff);
      completion.setHours(completion.getHours() + 1);

      get('flight-date').value = formatDate(takeoff);
      get('takeoff-time').value = formatTime(takeoff);
      get('completion-time').value = formatTime(completion);
    }

    function setMapStatus(message) {
      get('map-status').textContent = message;
    }

    function isPointInRing(latlng, ring) {
      if (!Array.isArray(ring) || ring.length < 3) return false;

      const x = latlng.lng;
      const y = latlng.lat;
      let inside = false;

      for (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) {
        const xi = ring[i][0];
        const yi = ring[i][1];
        const xj = ring[j][0];
        const yj = ring[j][1];
        const intersects = ((yi > y) !== (yj > y))
          && (x < ((xj - xi) * (y - yi)) / (yj - yi) + xi);

        if (intersects) inside = !inside;
      }

      return inside;
    }

    function isPointInPolygon(latlng, polygon) {
      if (!polygon.length || !isPointInRing(latlng, polygon[0])) return false;
      return !polygon.slice(1).some((hole) => isPointInRing(latlng, hole));
    }

    function isPointInGeometry(latlng, geometry) {
      if (!geometry) return false;

      if (geometry.type === 'Polygon') {
        return isPointInPolygon(latlng, geometry.coordinates);
      }

      if (geometry.type === 'MultiPolygon') {
        return geometry.coordinates.some((polygon) => isPointInPolygon(latlng, polygon));
      }

      if (geometry.type === 'GeometryCollection') {
        return Array.isArray(geometry.geometries)
          && geometry.geometries.some((item) => isPointInGeometry(latlng, item));
      }

      return false;
    }

    function isPointInGeoJson(latlng, geoJson) {
      if (!geoJson) return null;

      if (geoJson.type === 'FeatureCollection') {
        return Array.isArray(geoJson.features)
          && geoJson.features.some((feature) => isPointInGeometry(latlng, feature.geometry));
      }

      if (geoJson.type === 'Feature') {
        return isPointInGeometry(latlng, geoJson.geometry);
      }

      return isPointInGeometry(latlng, geoJson);
    }

    function selectLocation(latlng) {
      const latitude = latlng.lat.toFixed(6);
      const longitude = latlng.lng.toFixed(6);
      const insideFrz = isPointInGeoJson(latlng, frzGeoJson);
      const status = insideFrz === null
        ? 'FRZ status unavailable'
        : `${insideFrz ? 'inside' : 'outside'} the flight restriction zone`;

      if (selectedMarker) {
        selectedMarker.setLatLng(latlng);
      } else {
        selectedMarker = window.L.marker(latlng, { draggable: true }).addTo(map);
        selectedMarker.on('dragend', (event) => selectLocation(event.target.getLatLng()));
      }

      selectedMarker.bindPopup(`Selected location<br>${latitude}, ${longitude}<br>${status}`).openPopup();
      get('location-lat').value = latitude;
      get('location-lng').value = longitude;
      get('location-inside-frz').value = insideFrz === null ? '' : insideFrz ? 'yes' : 'no';
      get('location-description').value = `${latitude}, ${longitude}`;
      get('map-location-summary').value = `${latitude}, ${longitude} (${status})`;
      setMapStatus(`Selected ${latitude}, ${longitude} - ${status}.`);
    }

    function clearLocation() {
      if (selectedMarker) {
        selectedMarker.remove();
        selectedMarker = null;
      }

      get('location-lat').value = '';
      get('location-lng').value = '';
      get('location-inside-frz').value = '';
      get('location-description').value = '';
      get('map-location-summary').value = '';
      setMapStatus('Click the map to drop the requested flight location.');
    }

    async function loadFrzGeoJsonOverlay() {
      setMapStatus('Loading flight restriction zone...');

      try {
        const response = await fetch(FRZ_GEOJSON_ENDPOINT);
        if (!response.ok) {
          throw new Error(`FRZ request failed: ${response.status}`);
        }

        frzGeoJson = await response.json();
        const frzLayer = window.L.geoJSON(frzGeoJson, {
          interactive: false,
          style: {
            color: '#6c2bd9',
            fillColor: '#6c2bd9',
            fillOpacity: 0.12,
            weight: 2,
          },
          pointToLayer: (_feature, latlng) => window.L.circleMarker(latlng, {
            radius: 5,
            color: '#6c2bd9',
            fillColor: '#ffffff',
            fillOpacity: 1,
            weight: 2,
          }),
        }).addTo(map);

        const bounds = frzLayer.getBounds();
        if (bounds.isValid()) {
          map.fitBounds(bounds.pad(0.12));
        }

        setMapStatus('Click the map to drop the requested flight location.');
      } catch (error) {
        console.error('FRZ GeoJSON failed to load:', error);
        frzGeoJson = null;
        map.setView([ARP.lat, ARP.lng], 13);
        setMapStatus('FRZ overlay could not be loaded. Enter the location manually or click the map to capture coordinates.');
      }
    }

    async function initializeMap() {
      loadStylesheet(LEAFLET_CSS);
      await loadScript(LEAFLET_JS);

      map = window.L.map('drone-map', {
        scrollWheelZoom: false,
      }).setView([ARP.lat, ARP.lng], 13);

      window.L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 19,
        attribution: '&copy; OpenStreetMap contributors',
      }).addTo(map);

      window.L.circleMarker([ARP.lat, ARP.lng], {
        radius: 5,
        color: '#102233',
        fillColor: '#ffffff',
        fillOpacity: 1,
        weight: 2,
      }).bindPopup('Swansea Airport ARP').addTo(map);

      await loadFrzGeoJsonOverlay();
      map.on('click', (event) => selectLocation(event.latlng));
      get('clear-location').addEventListener('click', clearLocation);
    }

    function showNotification(message, isError = false) {
      const notification = get('notification');
      notification.textContent = message;
      notification.className = `drone-notification${isError ? ' error' : ''}`;
      requestAnimationFrame(() => notification.classList.add('show'));
      window.setTimeout(() => notification.classList.remove('show'), 5000);
    }

    function buildDroneRequestData(form) {
      const formData = new FormData(form);
      const data = {};

      formData.forEach((value, key) => {
        const fieldValue = String(value).trim();
        if (!fieldValue) return;
        const normalizedValue = key === 'operator_id' || key === 'flyer_id' ? fieldValue.toUpperCase() : fieldValue;

        if (key === 'maximum_elevation_ft_amsl') {
          data[key] = Number.parseInt(normalizedValue, 10);
        } else if (key === 'location_latitude' || key === 'location_longitude') {
          data[key] = Number.parseFloat(normalizedValue);
        } else {
          data[key] = normalizedValue;
        }
      });

      if (formData.get('flight_date') && formData.get('estimated_takeoff_time')) {
        data.estimated_takeoff_at = new Date(`${formData.get('flight_date')}T${formData.get('estimated_takeoff_time')}`).toISOString();
      }

      if (formData.get('flight_date') && formData.get('estimated_completion_time')) {
        data.estimated_completion_at = new Date(`${formData.get('flight_date')}T${formData.get('estimated_completion_time')}`).toISOString();
      }

      return data;
    }

    async function handleSubmit(event) {
      event.preventDefault();

      const form = event.currentTarget;
      const submitButton = get('submit-btn');
      const payload = buildDroneRequestData(form);

      get('loading').style.display = 'flex';
      submitButton.disabled = true;
      submitButton.textContent = 'Submitting...';

      try {
        const response = await fetch(DRONE_REQUEST_ENDPOINT, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(payload),
        });

        if (!response.ok) {
          const errorData = await response.json().catch(() => ({}));
          throw new Error(errorData.detail || `Submission failed: ${response.status}`);
        }

        const responseData = await response.json().catch(() => ({}));
        const referenceNumber = responseData?.reference_number;
        const referenceMessage = get('reference-number-message');
        const referenceNumberElement = get('reference-number');

        if (referenceNumber) {
          referenceNumberElement.textContent = referenceNumber;
          referenceMessage.hidden = false;
        } else {
          referenceNumberElement.textContent = '';
          referenceMessage.hidden = true;
        }

        form.style.display = 'none';
        const successMessage = get('success-message');
        successMessage.style.display = 'block';
        successMessage.focus({ preventScroll: true });
        window.scrollTo({ top: 0, behavior: 'smooth' });
        showNotification('Drone request submitted successfully!');
      } catch (error) {
        console.error('Error submitting drone request:', error);
        showNotification(`Error submitting drone request: ${error.message}`, true);
      } finally {
        get('loading').style.display = 'none';
        submitButton.disabled = false;
        submitButton.textContent = 'Submit Drone Request';
      }
    }

    function initializeUppercaseInputs() {
      ['operator-id', 'flyer-id'].forEach((id) => {
        const input = get(id);
        if (!input) return;

        input.addEventListener('input', () => {
          const cursorStart = input.selectionStart;
          const cursorEnd = input.selectionEnd;
          input.value = input.value.toUpperCase();
          input.setSelectionRange(cursorStart, cursorEnd);
        });
      });
    }

    document.addEventListener('DOMContentLoaded', () => {
      initializeTimeDropdowns();
      initializeUppercaseInputs();
      setDefaultDateTime();
      get('drone-form').addEventListener('submit', handleSubmit);
      initializeMap().catch((error) => {
        console.error('Leaflet map failed to load:', error);
        setMapStatus('Map could not be loaded. Enter the location manually.');
      });
    });
  })();
</script>

<style>
  .drone-shell {
    display: grid;
    gap: 1.25rem;
    margin-block: 1.5rem 0;
  }

  .drone-head {
    display: grid;
    gap: 0.55rem;
  }

  .drone-note {
    margin: 0;
    color: var(--muted);
    font-size: 0.95rem;
  }

  .drone-form {
    display: grid;
    gap: 1.2rem;
  }

  .drone-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
  }

  .drone-field {
    display: grid;
    gap: 0.4rem;
    align-content: start;
  }

  .drone-full {
    grid-column: 1 / -1;
  }

  .drone-field label {
    color: var(--text);
    font-size: 0.92rem;
    font-weight: 800;
  }

  .drone-field label span {
    color: var(--critical);
  }

  .drone-field input,
  .drone-field select,
  .drone-field textarea {
    width: 100%;
    min-height: 2.85rem;
    border: 1px solid rgba(16, 34, 51, 0.16);
    border-radius: 0.7rem;
    background: rgba(255, 255, 255, 0.88);
    color: var(--text);
    font: inherit;
    font-size: 1rem;
    padding: 0.7rem 0.82rem;
  }

  .drone-field textarea {
    min-height: 7.5rem;
    resize: vertical;
  }

  .uppercase-input {
    text-transform: uppercase;
  }

  .drone-field input:focus,
  .drone-field select:focus,
  .drone-field textarea:focus {
    outline: none;
    border-color: var(--brand-2);
    box-shadow: 0 0 0 0.2rem rgba(29, 118, 184, 0.16);
  }

  .drone-map-panel {
    display: grid;
    gap: 0.7rem;
    padding: 0.85rem;
    border: 1px solid rgba(16, 34, 51, 0.12);
    border-radius: 0.8rem;
    background: rgba(255, 255, 255, 0.6);
  }

  .drone-map-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
  }

  .drone-map-title {
    margin: 0;
    color: var(--text);
    font-weight: 800;
  }

  .drone-map-status {
    margin: 0.1rem 0 0;
    color: var(--muted);
    font-size: 0.9rem;
  }

  .drone-map {
    width: 100%;
    min-height: 31rem;
    border: 1px solid rgba(16, 34, 51, 0.14);
    border-radius: 0.75rem;
    overflow: hidden;
    background: #dcecff;
    z-index: 1;
  }

  .drone-map-location input {
    background: rgba(255, 255, 255, 0.72);
    color: var(--muted);
  }

  .drone-map-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.65rem 1rem;
    color: var(--muted);
    font-size: 0.88rem;
  }

  .drone-map-legend span {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
  }

  .legend-swatch {
    width: 0.8rem;
    height: 0.8rem;
    border-radius: 0.2rem;
    display: inline-block;
  }

  .legend-swatch.frz {
    border: 2px solid #6c2bd9;
    background: rgba(108, 43, 217, 0.12);
  }

  .legend-swatch.rpz {
    border: 2px solid #7c3aed;
    background: rgba(124, 58, 237, 0.18);
  }

  .legend-swatch.selected {
    border-radius: 50%;
    border: 2px solid #102233;
    background: #ffffff;
  }

  .drone-actions {
    display: flex;
    justify-content: flex-start;
    padding-top: 0.4rem;
  }

  .drone-actions .button,
  .drone-map-toolbar .button {
    cursor: pointer;
  }

  .drone-actions .button {
    border: 0;
  }

  .drone-actions .button:disabled {
    cursor: wait;
    opacity: 0.7;
  }

  .drone-loading {
    display: none;
    align-items: center;
    gap: 0.7rem;
    color: var(--brand);
    font-weight: 800;
  }

  .drone-spinner {
    width: 1.45rem;
    height: 1.45rem;
    border: 3px solid rgba(29, 118, 184, 0.18);
    border-top-color: var(--brand-2);
    border-radius: 50%;
    animation: drone-spin 0.8s linear infinite;
  }

  .drone-success {
    display: none;
    border-left-color: #257b4c;
  }

  .drone-notification {
    position: fixed;
    top: 1rem;
    right: 1rem;
    z-index: 60;
    max-width: min(24rem, calc(100vw - 2rem));
    padding: 0.85rem 1rem;
    border-radius: 0.8rem;
    background: #257b4c;
    color: white;
    box-shadow: var(--shadow);
    font-weight: 800;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-0.65rem);
    transition: opacity 0.18s ease, transform 0.18s ease;
  }

  .drone-notification.show {
    opacity: 1;
    transform: translateY(0);
  }

  .drone-notification.error {
    background: var(--critical);
  }

  @keyframes drone-spin {
    to {
      transform: rotate(360deg);
    }
  }

  @media (max-width: 720px) {
    .drone-grid {
      grid-template-columns: 1fr;
    }

    .drone-map-toolbar {
      align-items: stretch;
      flex-direction: column;
    }

    .drone-map {
      min-height: 25rem;
    }

    .drone-actions,
    .drone-actions .button,
    .drone-map-toolbar .button {
      width: 100%;
    }
  }
</style>
