function selectGrpcSource(source) {
  grpcSource = source;
  document.querySelectorAll('.grpc-source-btn').forEach(function(btn) {
    btn.classList.toggle('active', btn.dataset.source === source);
  });
  document.getElementById('grpc-src-proto').hidden = source !== 'proto';
  document.getElementById('grpc-src-reflection').hidden = source !== 'reflection';
  document.getElementById('grpc-src-manual').hidden = source !== 'manual';
  var detail = document.getElementById('grpc-method-detail');
  if (detail) detail.hidden = true;
  selectedRpcMethod = null;
}

function extractBlocks(text, keyword) {
  var blocks = [];
  var re = new RegExp(keyword + '\\s+(\\w+)\\s*\\{', 'g');
  var match;
  while ((match = re.exec(text)) !== null) {
    var name = match[1];
    var start = match.index + match[0].length;
    var depth = 1;
    var i = start;
    while (i < text.length && depth > 0) {
      if (text[i] === '{') depth++;
      else if (text[i] === '}') depth--;
      i++;
    }
    blocks.push({ name: name, body: text.slice(start, i - 1), start: match.index });
  }
  return blocks;
}

function stripProtoComments(text) {
  text = text.replace(/\/\*[\s\S]*?\*\//g, '');
  text = text.replace(/\/\/[^\n]*/g, '');
  return text;
}

function parseProto(text) {
  text = stripProtoComments(text);

  var pkg = '';
  var pkgMatch = text.match(/\bpackage\s+([\w.]+)\s*;/);
  if (pkgMatch) pkg = pkgMatch[1];

  var messages = {};
  extractBlocks(text, 'message').forEach(function(blk) {
    var fields = [];
    var fieldRe = /\b(repeated\s+)?([\w.]+)\s+(\w+)\s*=\s*\d+/g;
    var fm;
    while ((fm = fieldRe.exec(blk.body)) !== null) {
      if (['option', 'reserved', 'extensions', 'oneof'].indexOf(fm[2]) !== -1) continue;
      fields.push({ repeated: !!fm[1], type: fm[2], name: fm[3] });
    }
    messages[blk.name] = fields;
  });

  var streamingCount = 0;
  var services = [];

  extractBlocks(text, 'service').forEach(function(svc) {
    var methods = [];
    var rpcRe = /\brpc\s+(\w+)\s*\(\s*(stream\s+)?([\w.]+)\s*\)\s*returns\s*\(\s*(stream\s+)?([\w.]+)\s*\)/g;
    var rm;
    while ((rm = rpcRe.exec(svc.body)) !== null) {
      var streamIn = !!rm[2];
      var streamOut = !!rm[4];
      if (streamIn || streamOut) {
        streamingCount += 1;
      } else {
        var reqType = rm[3].split('.').pop();
        var resType = rm[5].split('.').pop();
        methods.push({ name: rm[1], request: reqType, response: resType });
      }
    }
    if (methods.length > 0) {
      services.push({ name: svc.name, methods: methods });
    }
  });

  return { package: pkg, services: services, messages: messages, streamingCount: streamingCount };
}

function renderServiceResults(parsed, ids) {
  protoParsed = parsed;
  selectedRpcMethod = null;

  var notice = document.getElementById(ids.notice);
  var countEl = document.getElementById(ids.count);
  if (notice) {
    notice.hidden = parsed.streamingCount <= 0;
    if (countEl && parsed.streamingCount > 0) countEl.textContent = parsed.streamingCount;
  }

  var totalMethods = parsed.services.reduce(function(n, s) { return n + s.methods.length; }, 0);
  var summaryEl = document.getElementById(ids.summary);
  if (summaryEl) {
    var servicesLabel = window.tPlural('wizard.grpc.services_label', parsed.services.length, {
      count: parsed.services.length,
    });
    var methodsLabel = window.tPlural('wizard.grpc.methods_label', totalMethods, {
      count: totalMethods,
    });
    summaryEl.textContent = tfKey('wizard.grpc.services_found', {
      services_label: servicesLabel,
      methods_label: methodsLabel,
    });
  }

  var listEl = document.getElementById(ids.list);
  if (!listEl) return;

  listEl.innerHTML = '';
  if (parsed.services.length === 0) {
    var emptyDiv = document.createElement('div');
    emptyDiv.className = 'proto-empty';
    emptyDiv.textContent = tKey('wizard.grpc.no_methods');
    listEl.appendChild(emptyDiv);
  } else {
    var svcTmpl = document.getElementById('tmpl-proto-service-group');
    var methodTmpl = document.getElementById('tmpl-proto-method-card');
    parsed.services.forEach(function(svc) {
      var svcNode = svcTmpl.content.cloneNode(true);
      svcNode.querySelector('.proto-service-name').textContent = svc.name;
      var grid = svcNode.querySelector('.proto-method-grid');
      svc.methods.forEach(function(m) {
        var mNode = methodTmpl.content.cloneNode(true);
        var btn = mNode.querySelector('.proto-method-card');
        btn.dataset.service = svc.name;
        btn.dataset.method = m.name;
        btn.dataset.req = m.request;
        btn.dataset.res = m.response;
        mNode.querySelector('.proto-method-name').textContent = m.name;
        mNode.querySelector('.proto-req-type').textContent = m.request;
        mNode.querySelector('.proto-res-type').textContent = m.response;
        grid.appendChild(mNode);
      });
      listEl.appendChild(svcNode);
    });
  }

  document.getElementById(ids.view).hidden = false;
  document.getElementById('grpc-method-detail').hidden = true;
}

function renderParsedProto(parsed) {
  var notice = document.getElementById('proto-streaming-text');
  if (notice && parsed && parsed.streamingCount) {
    notice.textContent = window.tPlural('wizard.step3.grpc.streaming_hidden', parsed.streamingCount, {
      count: parsed.streamingCount,
    });
  }
  renderServiceResults(parsed, {
    notice: 'proto-streaming-notice', count: 'proto-streaming-count',
    summary: 'proto-services-summary', list: 'proto-services-list', view: 'proto-parsed-view',
  });
}

function renderReflectionResult(parsed) {
  var reflectText = document.querySelector('#reflect-streaming-notice .info-callout-text');
  if (reflectText && parsed && parsed.streamingCount) {
    reflectText.textContent = window.tPlural('wizard.step3.grpc.streaming_hidden', parsed.streamingCount, {
      count: parsed.streamingCount,
    });
  }
  renderServiceResults(parsed, {
    notice: 'reflect-streaming-notice', count: 'reflect-streaming-count',
    summary: 'reflect-services-summary', list: 'reflect-services-list', view: 'reflect-parsed-view',
  });
}

function selectRpcMethod(btn) {
  document.querySelectorAll('.proto-method-card').forEach(function(b) { b.classList.remove('active'); });
  btn.classList.add('active');

  var svcName = btn.dataset.service;
  var methodName = btn.dataset.method;
  var reqType = btn.dataset.req;
  var resType = btn.dataset.res;

  selectedRpcMethod = { service: svcName, method: methodName, request: reqType, response: resType };

  var pkg = protoParsed && protoParsed.package ? protoParsed.package + '.' : '';
  var grpcPath = '/' + pkg + svcName + '/' + methodName;

  var pathEl = document.getElementById('grpc-path-value');
  if (pathEl) pathEl.textContent = grpcPath;

  var sub = document.getElementById('grpc-method-subtitle');
  if (sub) sub.textContent = 'rpc ' + methodName + ' (' + reqType + ') returns (' + resType + ')';

  var reqTypeEl = document.getElementById('grpc-req-type');
  var resTypeEl = document.getElementById('grpc-res-type');
  if (reqTypeEl) reqTypeEl.textContent = reqType;
  if (resTypeEl) resTypeEl.textContent = resType;

  var sigGrid = document.getElementById('grpc-detail-sig');
  if (sigGrid) sigGrid.hidden = false;

  renderFieldList('grpc-req-fields', reqType);
  renderFieldList('grpc-res-fields', resType);

  document.getElementById('grpc-method-detail').hidden = false;
}

function renderFieldList(elId, typeName) {
  var el = document.getElementById(elId);
  if (!el) return;
  var fields = protoParsed && protoParsed.messages[typeName];
  el.innerHTML = '';
  if (!fields || fields.length === 0) {
    var emptyEl = document.createElement('div');
    emptyEl.className = 'proto-field-empty';
    emptyEl.textContent = '';
    emptyEl.appendChild(document.createTextNode(tKey('wizard.grpc.fields_unresolved')));
    emptyEl.appendChild(document.createElement('br'));
    var hint = document.createElement('span');
    hint.style.color = 'var(--text-muted)';
    hint.style.fontSize = '11px';
    hint.textContent = tKey('wizard.grpc.fields_unresolved_body');
    emptyEl.appendChild(hint);
    el.appendChild(emptyEl);
    return;
  }
  var fieldTmpl = document.getElementById('tmpl-proto-field-row');
  fields.forEach(function(f) {
    var node = fieldTmpl.content.cloneNode(true);
    node.querySelector('.proto-field-name').textContent = f.name;
    node.querySelector('.proto-field-type').textContent = (f.repeated ? 'repeated ' : '') + f.type;
    el.appendChild(node);
  });
}

function handleProtoFile(event) {
  var file = event.target.files[0];
  if (!file) return;
  var reader = new FileReader();
  reader.onload = function(e) {
    wizardProtoUpload = { fileName: file.name, content: e.target.result };
    showProtoFileInfo(file.name, file.size);
    var parsed = parseProto(e.target.result);
    renderParsedProto(parsed);
  };
  reader.readAsText(file);
}

function handleProtoDrop(event) {
  event.preventDefault();
  var dropzone = document.getElementById('proto-dropzone');
  if (dropzone) dropzone.classList.remove('drag-over');
  var file = event.dataTransfer.files[0];
  if (!file || !file.name.endsWith('.proto')) return;
  var reader = new FileReader();
  reader.onload = function(e) {
    wizardProtoUpload = { fileName: file.name, content: e.target.result };
    showProtoFileInfo(file.name, file.size);
    renderParsedProto(parseProto(e.target.result));
  };
  reader.readAsText(file);
}

function showProtoFileInfo(name, size) {
  var dropzone = document.getElementById('proto-dropzone');
  var info = document.getElementById('proto-file-info');
  var nameEl = document.getElementById('proto-file-name');
  var sizeEl = document.getElementById('proto-file-size');
  if (dropzone) dropzone.hidden = true;
  if (info) info.hidden = false;
  if (nameEl) nameEl.textContent = name;
  if (sizeEl) sizeEl.textContent = (size / 1024).toFixed(1) + ' KB';
  document.getElementById('proto-paste-area').hidden = true;
  document.getElementById('proto-paste-btn').textContent = 'Paste content';
}

function resetProto() {
  var dropzone = document.getElementById('proto-dropzone');
  var info = document.getElementById('proto-file-info');
  var parsedView = document.getElementById('proto-parsed-view');
  if (dropzone) dropzone.hidden = false;
  if (info) info.hidden = true;
  if (parsedView) parsedView.hidden = true;
  var fileInput = document.getElementById('proto-file-input');
  if (fileInput) fileInput.value = '';
  protoParsed = null;
  selectedRpcMethod = null;
  wizardProtoUpload = null;
}

function toggleProtoPaste() {
  var area = document.getElementById('proto-paste-area');
  var btn = document.getElementById('proto-paste-btn');
  if (!area) return;
  var open = !area.hidden;
  area.hidden = open;
  if (btn) btn.textContent = open ? 'Paste content' : 'Cancel paste';
  if (!open) {
    var ta = document.getElementById('proto-paste-input');
    if (ta) setTimeout(function() { ta.focus(); }, 50);
  }
}

function cancelProtoPaste() {
  var area = document.getElementById('proto-paste-area');
  var btn = document.getElementById('proto-paste-btn');
  if (area) area.hidden = true;
  if (btn) btn.textContent = 'Paste content';
}

function parseProtoPasted() {
  var ta = document.getElementById('proto-paste-input');
  if (!ta || !ta.value.trim()) return;
  var parsed = parseProto(ta.value);
  wizardProtoUpload = { fileName: 'pasted.proto', content: ta.value };
  document.getElementById('proto-paste-area').hidden = true;
  var dropzone = document.getElementById('proto-dropzone');
  if (dropzone) dropzone.hidden = true;
  var info = document.getElementById('proto-file-info');
  var nameEl = document.getElementById('proto-file-name');
  var sizeEl = document.getElementById('proto-file-size');
  if (info) info.hidden = false;
  if (nameEl) nameEl.textContent = 'pasted.proto';
  if (sizeEl) sizeEl.textContent = (ta.value.length / 1024).toFixed(1) + ' KB';
  renderParsedProto(parsed);
}

var REFLECTION_MOCK = {
  package: 'acme.v1',
  streamingCount: 2,
  services: [
    { name: 'ContactService', methods: [
      { name: 'GetContact', request: 'GetContactRequest', response: 'Contact' },
      { name: 'CreateContact', request: 'CreateContactRequest', response: 'Contact' },
      { name: 'UpdateContact', request: 'UpdateContactRequest', response: 'Contact' },
      { name: 'DeleteContact', request: 'DeleteContactRequest', response: 'DeleteContactResponse' },
    ]},
    { name: 'CompanyService', methods: [
      { name: 'GetCompany', request: 'GetCompanyRequest', response: 'Company' },
      { name: 'ListCompanies', request: 'ListCompaniesRequest', response: 'ListCompaniesResponse' },
    ]},
  ],
  messages: {
    'GetContactRequest': [{ type: 'string', name: 'id' }],
    Contact: [{ type: 'string', name: 'id' }, { type: 'string', name: 'first_name' }, { type: 'string', name: 'last_name' }, { type: 'string', name: 'email' }, { type: 'string', name: 'company_id' }, { type: 'string', name: 'created_at' }],
    'CreateContactRequest': [{ type: 'string', name: 'first_name' }, { type: 'string', name: 'last_name' }, { type: 'string', name: 'email' }, { type: 'string', name: 'company_id' }],
    'UpdateContactRequest': [{ type: 'string', name: 'id' }, { type: 'string', name: 'first_name' }, { type: 'string', name: 'last_name' }, { type: 'string', name: 'email' }],
    'DeleteContactRequest': [{ type: 'string', name: 'id' }],
    'DeleteContactResponse': [{ type: 'bool', name: 'success' }],
    'GetCompanyRequest': [{ type: 'string', name: 'id' }],
    Company: [{ type: 'string', name: 'id' }, { type: 'string', name: 'name' }, { type: 'string', name: 'domain' }, { type: 'int32', name: 'employee_count' }],
    'ListCompaniesRequest': [{ type: 'int32', name: 'page' }, { type: 'int32', name: 'page_size' }, { type: 'string', name: 'query' }],
    'ListCompaniesResponse': [{ type: 'Company', name: 'companies', repeated: true }, { type: 'int32', name: 'total' }],
  },
};

function startReflection() {
  goToStep(5);
  showWizardLiveStatus(
    tKey('wizard.grpc.discovery_title'),
    tKey('wizard.grpc.discovery_body')
  );
}

function grpcManualRouteInput(val) {
  var detail = document.getElementById('grpc-method-detail');
  var sigGrid = document.getElementById('grpc-detail-sig');
  if (!val || !val.startsWith('/') || val.indexOf('/', 1) === -1) {
    if (detail) detail.hidden = true;
    return;
  }
  var parts = val.replace(/^\//, '').split('/');
  var servicePart = parts[0] || '';
  var methodName = parts[1] || '';
  var serviceName = servicePart.split('.').pop();

  var pathEl = document.getElementById('grpc-path-value');
  if (pathEl) pathEl.textContent = val;

  var sub = document.getElementById('grpc-method-subtitle');
  if (sub) sub.textContent = serviceName + '/' + methodName;

  if (sigGrid) sigGrid.hidden = true;

  grpcManualTypeInput();
  if (detail) detail.hidden = false;
}

function grpcManualTypeInput() {
  var reqInput = document.getElementById('grpc-manual-req-type');
  var resInput = document.getElementById('grpc-manual-res-type');
  var reqTypeEl = document.getElementById('grpc-req-type');
  var resTypeEl = document.getElementById('grpc-res-type');
  if (reqTypeEl) reqTypeEl.textContent = (reqInput && reqInput.value.trim()) || '—';
  if (resTypeEl) resTypeEl.textContent = (resInput && resInput.value.trim()) || '—';
}
