function downloadTextFile(fileName, content, mimeType) {
  var blob = new Blob([content], { type: mimeType || 'text/plain;charset=utf-8' });
  var url = URL.createObjectURL(blob);
  var link = document.createElement('a');
  link.href = url;
  link.download = fileName;
  link.click();
  URL.revokeObjectURL(url);
}

async function exportWizardYaml() {
  await persistCurrentDraft(true);
  var yaml = await window.CrankApi.exportOperation(wizardWorkspaceId, wizardEditId, {
    mode: 'portable',
    version: currentDraftVersion(),
  });
  downloadTextFile((textValue('tool-name') || 'operation') + '.yaml', yaml, 'application/yaml');
  showWizardLiveStatus(tKey('wizard.yaml.exported'), tKey('wizard.yaml.exported_body'));
}

async function importWizardYaml() {
  if (!wizardWorkspaceId) {
    throw new Error(tKey('wizard.error.no_workspace'));
  }
  var yamlDocument = textValue('wizard-import-yaml-text');
  if (!yamlDocument) {
    showWizardLiveStatus(tKey('wizard.yaml.none'), tKey('wizard.yaml.none_body'), true);
    return;
  }
  var imported = await window.CrankApi.importOperation(wizardWorkspaceId, yamlDocument, 'upsert');
  showWizardLiveStatus(tKey('wizard.yaml.imported'), tKey('wizard.yaml.imported_body'));
  window.location.href = window.location.pathname + '?mode=edit&operationId=' + encodeURIComponent(imported.operation_id);
}

async function publishWizardOperation() {
  await persistCurrentDraft(true);
  var published = await window.CrankApi.publishOperation(
    wizardWorkspaceId,
    wizardEditId,
    currentDraftVersion()
  );
  await refreshCurrentOperationState();
  showWizardLiveStatus(
    tKey('wizard.publish.done'),
    tfKey('wizard.publish.done_body', { version: published.published_version })
  );
}

function handleImportYamlFileSelection(event) {
  var file = event.target.files && event.target.files[0];
  if (!file) return;
  var reader = new FileReader();
  reader.onload = function(loadEvent) {
    setValue('wizard-import-yaml-text', loadEvent.target.result || '');
    showWizardLiveStatus(tKey('wizard.yaml.loaded'), tKey('wizard.yaml.loaded_body'));
  };
  reader.readAsText(file);
}

function handleDescriptorSetSelection(event) {
  var file = event.target.files && event.target.files[0];
  if (!file) return;
  var reader = new FileReader();
  reader.onload = function(loadEvent) {
    wizardDescriptorSetUpload = {
      fileName: file.name,
      bytes: new Uint8Array(loadEvent.target.result),
    };
    var fileNameEl = document.getElementById('wizard-descriptor-set-name');
    if (fileNameEl) fileNameEl.textContent = file.name;
    showWizardLiveStatus(tKey('wizard.descriptor.selected'), tKey('wizard.descriptor.selected_body'));
  };
  reader.readAsArrayBuffer(file);
}

function handleSoapWsdlSelection(event) {
  var file = event.target.files && event.target.files[0];
  if (!file) return;
  var reader = new FileReader();
  reader.onload = function(loadEvent) {
    wizardSoapWsdlUpload = {
      fileName: file.name,
      bytes: new Uint8Array(loadEvent.target.result),
    };
    var fileNameEl = document.getElementById('wizard-soap-wsdl-name');
    if (fileNameEl) fileNameEl.textContent = file.name;
    showWizardLiveStatus(tKey('wizard.step3.soap.wsdl_selected'), tKey('wizard.step3.soap.wsdl_selected_body'));
  };
  reader.readAsArrayBuffer(file);
}

function handleSoapXsdSelection(event) {
  var file = event.target.files && event.target.files[0];
  if (!file) return;
  var reader = new FileReader();
  reader.onload = function(loadEvent) {
    wizardSoapXsdUpload = {
      fileName: file.name,
      bytes: new Uint8Array(loadEvent.target.result),
    };
    var fileNameEl = document.getElementById('wizard-soap-xsd-name');
    if (fileNameEl) fileNameEl.textContent = file.name;
    showWizardLiveStatus(tKey('wizard.step3.soap.xsd_selected'), tKey('wizard.step3.soap.xsd_selected_body'));
  };
  reader.readAsArrayBuffer(file);
}

function renderDescriptorServiceList(services) {
  grpcDescriptorServices = services || [];
  var summaryEl = document.getElementById('wizard-descriptor-services-summary');
  var listEl = document.getElementById('wizard-descriptor-services-list');
  if (!summaryEl || !listEl) return;

  var methodCount = grpcDescriptorServices.reduce(function(total, service) {
    return total + ((service.methods || []).length);
  }, 0);
  summaryEl.textContent = grpcDescriptorServices.length
    ? tfKey('wizard.grpc.services_discovered', { services: grpcDescriptorServices.length, methods: methodCount })
    : tKey('wizard.grpc.services_none');
  listEl.innerHTML = '';

  grpcDescriptorServices.forEach(function(service, serviceIndex) {
    var group = document.createElement('div');
    group.className = 'config-card';
    group.style.marginBottom = '0';

    var body = document.createElement('div');
    body.className = 'config-card-body';
    body.style.padding = '16px';
    body.style.gap = '10px';

    var title = document.createElement('div');
    title.className = 'config-card-title';
    title.textContent = (service.package ? service.package + '.' : '') + service.service;
    body.appendChild(title);

    (service.methods || []).forEach(function(method, methodIndex) {
      var button = document.createElement('button');
      button.type = 'button';
      button.className = 'btn-ghost-sm';
      button.style.width = '100%';
      button.style.justifyContent = 'space-between';
      button.textContent = method.name;
      button.addEventListener('click', function() {
        applyDiscoveredGrpcMethod(serviceIndex, methodIndex);
      });
      body.appendChild(button);
    });

    group.appendChild(body);
    listEl.appendChild(group);
  });
}

function applyDiscoveredGrpcMethod(serviceIndex, methodIndex) {
  var service = grpcDescriptorServices[serviceIndex];
  var method = service && service.methods ? service.methods[methodIndex] : null;
  if (!service || !method) return;

  var route = '/' + (service.package ? service.package + '.' : '') + service.service + '/' + method.name;
  selectGrpcSource('manual');
  setValue('grpc-manual-route', route);
  setValue('grpc-manual-req-type', method.name + 'Request');
  setValue('grpc-manual-res-type', method.name + 'Response');
  grpcManualRouteInput(route);
  grpcManualTypeInput();
  setValue('tool-input-schema', JSON.stringify(crankSchemaToJsonSchema(method.input_schema), null, 2));
  setValue('tool-output-schema', JSON.stringify(crankSchemaToJsonSchema(method.output_schema), null, 2));
  showWizardLiveStatus(tKey('wizard.descriptor.applied'), tKey('wizard.descriptor.applied_body'));
}

async function uploadDescriptorSetAndDiscover() {
  var hasSavedDescriptor = !!(
    wizardCurrentVersion
    && wizardCurrentVersion.target
    && wizardCurrentVersion.target.kind === 'grpc'
    && wizardCurrentVersion.target.descriptor_ref
  );

  if (!wizardDescriptorSetUpload && !hasSavedDescriptor) {
    showWizardLiveStatus(tKey('wizard.descriptor.no_file'), tKey('wizard.descriptor.no_file_body'), true);
    return;
  }

  await persistCurrentDraft(true);

  var services = await window.CrankApi.listGrpcServices(
    wizardWorkspaceId,
    wizardEditId,
    currentDraftVersion()
  );
  renderDescriptorServiceList(services.services || []);
  showWizardLiveStatus(tKey('wizard.descriptor.discovered'), tKey('wizard.descriptor.discovered_body'));
}

function renderSoapServiceCatalog(services) {
  soapServiceCatalog = services || [];
  var summaryEl = document.getElementById('wizard-soap-services-summary');
  var listEl = document.getElementById('wizard-soap-services-list');
  if (!summaryEl || !listEl) return;

  var portCount = 0;
  var operationCount = 0;
  soapServiceCatalog.forEach(function(service) {
    portCount += (service.ports || []).length;
    (service.ports || []).forEach(function(port) {
      operationCount += (port.operations || []).length;
    });
  });

  summaryEl.textContent = soapServiceCatalog.length
    ? tfKey('wizard.step3.soap.services_discovered', {
        services: soapServiceCatalog.length,
        ports: portCount,
        operations: operationCount
      })
    : tKey('wizard.step3.soap.services_none');
  listEl.innerHTML = '';

  soapServiceCatalog.forEach(function(service, serviceIndex) {
    var group = document.createElement('div');
    group.className = 'config-card';
    group.style.marginBottom = '0';

    var body = document.createElement('div');
    body.className = 'config-card-body';
    body.style.padding = '16px';
    body.style.gap = '10px';

    var title = document.createElement('div');
    title.className = 'config-card-title';
    title.textContent = service.service_name;
    body.appendChild(title);

    (service.ports || []).forEach(function(port, portIndex) {
      var portLabel = document.createElement('div');
      portLabel.className = 'form-hint';
      portLabel.textContent = port.port_name + ' · ' + port.soap_version;
      body.appendChild(portLabel);

      (port.operations || []).forEach(function(operation, operationIndex) {
        var button = document.createElement('button');
        button.type = 'button';
        button.className = 'btn-ghost-sm';
        button.style.width = '100%';
        button.style.justifyContent = 'space-between';
        button.textContent = operation.operation_name;
        button.addEventListener('click', function() {
          applyDiscoveredSoapOperation(serviceIndex, portIndex, operationIndex);
        });
        body.appendChild(button);
      });
    });

    group.appendChild(body);
    listEl.appendChild(group);
  });
}

function applyDiscoveredSoapOperation(serviceIndex, portIndex, operationIndex) {
  var service = soapServiceCatalog[serviceIndex];
  var port = service && service.ports ? service.ports[portIndex] : null;
  var operation = port && port.operations ? port.operations[operationIndex] : null;
  if (!service || !port || !operation) return;

  setValue('soap-service-name', service.service_name);
  setValue('soap-port-name', port.port_name);
  setValue('soap-operation-name', operation.operation_name);
  setValue('soap-version', port.soap_version || 'soap_11');
  setValue('soap-action', operation.soap_action || '');
  setValue('soap-binding-style', operation.binding_style || 'document_literal');
  if (!textValue('soap-endpoint-override') && port.endpoint) {
    setValue('soap-endpoint-override', port.endpoint);
  }

  showWizardLiveStatus(tKey('wizard.step3.soap.applied'), tKey('wizard.step3.soap.applied_body'));
}

async function uploadSoapArtifactsAndInspect() {
  var hasSavedWsdl = !!(
    wizardCurrentVersion
    && wizardCurrentVersion.target
    && wizardCurrentVersion.target.kind === 'soap'
    && wizardCurrentVersion.target.wsdl_ref
    && wizardCurrentVersion.target.wsdl_ref !== 'sample_wsdl_pending'
  );

  if (!wizardSoapWsdlUpload && !hasSavedWsdl) {
    showWizardLiveStatus(tKey('wizard.step3.soap.no_wsdl_error'), tKey('wizard.step3.soap.no_wsdl_error_body'), true);
    return;
  }

  await persistCurrentDraft(true);

  var services = await window.CrankApi.listSoapServices(
    wizardWorkspaceId,
    wizardEditId,
    currentDraftVersion()
  );
  renderSoapServiceCatalog(services.services || []);
  showWizardLiveStatus(tKey('wizard.step3.soap.discovered'), tKey('wizard.step3.soap.discovered_body'));
}
