import html
import json
from mcp.server.fastmcp import FastMCP


def register(mcp: FastMCP):

    @mcp.tool()
    def fluig_scaffold_form(
        nome_processo: str,
        campos: str,
        tem_anexo: bool = False,
        tem_abas: bool = False,
    ) -> str:
        """
        Gera o HTML completo de um formulario Fluig seguindo as convencoes do skill
        fluig-formularios: imports obrigatorios (CSS/JS Style Guide, jQuery 3.7.1,
        jQuery UI 1.13.2, Mustache 2.3.2), wrapper fluig-style-guide, painel fixo
        'Dados da Solicitacao', campo oculto num_solicitacao, referencias a custom.js
        e custom.css, e nomes de campo em snake_case (max 30 chars).

        Args:
            nome_processo: Nome do processo. Ex: 'Admissao de Colaborador'.
            campos: JSON string com lista de campos.
                    Ex: '[{"nome":"nome_completo","label":"Nome Completo","tipo":"text","obrigatorio":true,"col":"6"}]'.
                    Tipos suportados: text, textarea, select, date, checkbox, radio, autocomplete.
                    Para select inclua "opcoes": ["Op1","Op2"].
                    Para autocomplete inclua "dataset": "NomeDataset" e "campo_retorno": "campo".
                    O campo "col" define a largura (3-12), padrao 6. col-xs-12 e adicionado automaticamente.
            tem_anexo: Se true, inclui componente de anexo de arquivos.
            tem_abas: Se true, gera campos distribuidos em abas.
        """
        try:
            lista_campos = json.loads(campos)
        except json.JSONDecodeError:
            return "Erro: 'campos' deve ser um JSON valido. Ex: [{\"nome\":\"campo\",\"label\":\"Label\",\"tipo\":\"text\"}]"

        campos_html = _gerar_campos(lista_campos)
        anexo_html = _gerar_anexo() if tem_anexo else ""

        if tem_abas and lista_campos:
            conteudo = _gerar_abas(campos_html, lista_campos)
        else:
            nome_esc = html.escape(nome_processo)
            conteudo = f"""
  <!-- Painel fixo: Dados da Solicitacao -->
  <div class="panel panel-default">
    <div class="panel-heading">
      <h3 class="panel-title">Dados da Solicitacao</h3>
    </div>
    <div class="panel-body">
      <div class="row">
        {"".join(campos_html)}
      </div>
      {anexo_html}
    </div>
  </div>"""

        form_id = _camel(nome_processo)

        return f"""<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <!-- CSS Style Guide (obrigatorio) -->
  <link rel="stylesheet" href="/style-guide/css/fluig-style-guide.min.css" />
  <link rel="stylesheet" href="/style-guide/css/fluig-style-guide-ie.min.css" />
  <!-- CSS customizado do formulario -->
  <link rel="stylesheet" href="custom.css" />
</head>
<body>
<div class="fluig-style-guide">
  <form id="form{form_id}" name="form{form_id}">

    <!-- Campo oculto de controle -->
    <input type="hidden" id="num_solicitacao" name="num_solicitacao" value="" />

{conteudo}

  </form>
</div>

<!-- JS obrigatorios -->
<script src="/style-guide/js/fluig-style-guide.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-ui@1.13.2/dist/jquery-ui.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mustache@2.3.2/mustache.min.js"></script>
<!-- JS customizado do formulario -->
<script src="custom.js"></script>
</body>
</html>"""

    @mcp.tool()
    def fluig_scaffold_dataset(
        nome: str,
        descricao: str,
        colunas: str,
        tipo: str = "customizado",
    ) -> str:
        """
        Gera o esqueleto JS completo de um dataset Fluig com createDataset e getDataset.

        Args:
            nome: Nome do dataset. Ex: 'ds_colaboradores_departamento'.
            descricao: Descricao do que o dataset faz.
            colunas: JSON string com lista de nomes de colunas. Ex: '["codigo","nome","departamento"]'.
            tipo: 'customizado' (padrao) ou 'sincronizado'.
        """
        try:
            lista_colunas = json.loads(colunas)
        except json.JSONDecodeError:
            return "Erro: 'colunas' deve ser um JSON array valido. Ex: [\"col1\",\"col2\"]"

        colunas_add = "\n  ".join([f'dataset.addColumn("{c}");' for c in lista_colunas])
        colunas_value = ", ".join([f'"{c}"' for c in lista_colunas])

        if tipo == "sincronizado":
            return f"""/**
 * Dataset: {nome}
 * Descricao: {descricao}
 * Tipo: Sincronizado
 */
function createDataset(fields, constraints, sortFields) {{
  var dataset = DatasetFactory.createDataset();

  {colunas_add}

  // TODO: implementar logica de sincronizacao
  // Exemplo com DatasetFactory:
  // var sourceDs = DatasetFactory.getDataset("OutroDataset", null, constraints, null);
  // for (var i = 0; i < sourceDs.values.length; i++) {{
  //   dataset.addRow([sourceDs.getValue(i, "{lista_colunas[0] if lista_colunas else 'campo'}"]]);
  // }}

  return dataset;
}}
"""

        return f"""/**
 * Dataset: {nome}
 * Descricao: {descricao}
 * Colunas: {colunas_value}
 */
function createDataset(fields, constraints, sortFields) {{
  var dataset = DatasetFactory.createDataset();

  {colunas_add}

  // Mapeia constraints recebidas para facilitar acesso
  var filtros = {{}};
  if (constraints) {{
    for (var i = 0; i < constraints.length; i++) {{
      filtros[constraints[i].fieldName] = constraints[i].initialValue;
    }}
  }}

  // TODO: implementar a logica de busca/montagem dos dados
  // Exemplo consultando outro dataset:
  // var dsOrigem = DatasetFactory.getDataset("ColleagueDS", null, null, null);
  // for (var i = 0; i < dsOrigem.values.length; i++) {{
  //   var linha = dsOrigem.values[i];
  //   if (!filtros["campo"] || linha["campo"] == filtros["campo"]) {{
  //     dataset.addRow([linha["campo1"], linha["campo2"]]);
  //   }}
  // }}

  return dataset;
}}
"""

    @mcp.tool()
    def fluig_scaffold_widget(
        nome: str,
        descricao: str,
        tem_rest_call: bool = False,
    ) -> str:
        """
        Gera a estrutura completa de um widget Fluig com application.info,
        view.ftl, edit.ftl, JS (SuperWidget.extend), CSS e .properties i18n,
        seguindo as convencoes do skill fluig-widgets.

        Args:
            nome: Nome do widget sem espacos. Ex: 'MeuWidget'.
            descricao: Descricao do widget.
            tem_rest_call: Se true, inclui exemplo de chamada REST no widget.
        """
        widget_id = _kebab(nome)

        rest_example = ""
        if tem_rest_call:
            rest_example = """
      // Exemplo de chamada REST
      var self = this;
      WCMAPI.Read({
        type: "GET",
        url: WCMAPI.getServerURL() + "/api/public/ecm/dataset/availableDatasets",
        success: function(data) {
          console.log("Datasets:", data);
        },
        error: function(xhr, status, error) {
          console.error("Erro na chamada REST:", error);
        }
      });"""

        return f"""===== application.info =====
application.code={widget_id}
application.title={descricao}
application.description={descricao}
application.category=fluig
application.type=widget
application.renderer=freemarker

===== view.ftl =====
<div id="${{instanceId}}" class="super-widget wcm-widget-class fluig-style-guide {widget_id}" data-params="instance.init">
  <div class="panel panel-default">
    <div class="panel-heading">
      <h3 class="panel-title">{html.escape(descricao)}</h3>
    </div>
    <div class="panel-body">
      <div id="${{instanceId}}-content">
        <!-- conteudo renderizado pelo Mustache -->
      </div>
    </div>
  </div>
</div>

===== edit.ftl =====
<div id="${{instanceId}}-edit" class="super-widget wcm-widget-class fluig-style-guide {widget_id}" data-params="instance.edit">
  <div class="form-group">
    <label>Configuracoes</label>
    <p class="help-block">Configure as preferencias do widget.</p>
    <input type="text" class="form-control" id="${{instanceId}}-config" name="config" value="" />
  </div>
  <div class="form-group">
    <button type="button" class="btn btn-primary" id="${{instanceId}}-save">Salvar</button>
  </div>
</div>

<script>
// edit.ftl save pattern via WCMSpaceAPI
(function() {{
  var instanceId = "${{instanceId}}";
  $("#" + instanceId + "-save").on("click", function() {{
    var config = $("#" + instanceId + "-config").val();
    WCMSpaceAPI.PageService.EDITPREFERENCES({{
      async: true,
      success: function(data) {{
        console.log("Preferencias salvas");
      }},
      fail: function(xhr, message, errorData) {{
        console.error("Erro ao salvar:", message);
      }}
    }});
  }});
}})();
</script>

===== {widget_id}.js =====
var {nome} = SuperWidget.extend({{

  init: function() {{
    var self = this;
    var container = $("#" + self.instanceId + "-content");
{rest_example}

    // Inicializar componentes apos renderizacao
    container.on("click", ".btn-acao", function() {{
      self._handleAcao($(this).data("id"));
    }});
  }},

  _handleAcao: function(id) {{
    // TODO: implementar logica de acao
    console.log("Acao disparada para ID:", id);
  }},

  _renderizar: function(dados) {{
    var self = this;
    var tmpl = Mustache.to_html(
      $("#{widget_id}-template").html(),
      {{ itens: dados }}
    );
    $("#" + self.instanceId + "-content").html(tmpl);
  }}

}});

===== {widget_id}.css =====
/* Estilos customizados do widget {nome} */
.{widget_id} {{
  /* TODO: adicionar estilos */
}}

===== i18n/{widget_id}.properties =====
{widget_id}.title={descricao}
{widget_id}.description={descricao}
"""

    @mcp.tool()
    def fluig_scaffold_evento_workflow(
        nome_evento: str,
        descricao_logica: str,
    ) -> str:
        """
        Gera script de evento de processo workflow com assinatura correta da plataforma Fluig.

        Args:
            nome_evento: Nome do evento. Suportados:
                'afterProcessCreate', 'afterTaskComplete', 'beforeTaskSave',
                'beforeSendData', 'calculateAgreement', 'afterCancelProcess',
                'afterProcessFinish', 'subProcessCreated'.
            descricao_logica: O que o evento deve fazer. Ex: 'Mover anexos para pasta GED do cliente'.
        """
        assinaturas = {
            "afterProcessCreate": {
                "sig": "function afterProcessCreate(colleagueId)",
                "vars": """  var numProcesso = getValue("WKNumProces");
  var numState = getValue("WKNumState");
  log.info("afterProcessCreate - processo: " + numProcesso + " estado: " + numState);
""",
                "body": """  // hAPI disponivel para manipular campos do formulario
  // hAPI.setCardValue("campo", "valor");
""",
            },
            "afterTaskComplete": {
                "sig": "function afterTaskComplete(colleagueId, nextSequenceId, userList)",
                "vars": """  var numProcesso = getValue("WKNumProces");
  var numState = getValue("WKNumState");
  log.info("afterTaskComplete - processo: " + numProcesso + " sequencia: " + nextSequenceId);
""",
                "body": """  // Leitura e escrita de campos do formulario via hAPI
  // var valor = hAPI.getCardValue("campo");
  // hAPI.setCardValue("campo", "novoValor");
""",
            },
            "beforeTaskSave": {
                "sig": "function beforeTaskSave(colleagueId, nextSequenceId, userList)",
                "vars": """  var numProcesso = getValue("WKNumProces");
  var numState = getValue("WKNumState");
  log.info("beforeTaskSave - processo: " + numProcesso);
""",
                "body": """  // Validacao antes de salvar a tarefa
  // var campo = hAPI.getCardValue("campo");
  // if (!campo || campo.trim() === "") {
  //   throw "Campo obrigatorio nao preenchido.";
  // }
""",
            },
            "beforeSendData": {
                "sig": "function beforeSendData(colleagueId, nextSequenceId, userList)",
                "vars": """  var numProcesso = getValue("WKNumProces");
  var numState = getValue("WKNumState");
  log.info("beforeSendData - processo: " + numProcesso);
""",
                "body": """  // Analytics / SLA / log de tempo
  // var inicio = hAPI.getCardValue("data_inicio");
  // var agora = new java.util.Date();
""",
            },
            "calculateAgreement": {
                "sig": "function calculateAgreement(processId, visibleCards, agreementData)",
                "vars": """  log.info("calculateAgreement - processo: " + processId);
""",
                "body": """  // Multi-aprovacao: definir regras de consenso
  // agreementData contém informacoes dos aprovadores
  // Retornar true para aprovar, false para rejeitar
  return true;
""",
            },
            "afterCancelProcess": {
                "sig": "function afterCancelProcess(colleagueId)",
                "vars": """  var numProcesso = getValue("WKNumProces");
  log.info("afterCancelProcess - processo: " + numProcesso);
""",
                "body": """  // Limpeza apos cancelamento do processo
""",
            },
            "afterProcessFinish": {
                "sig": "function afterProcessFinish(colleagueId)",
                "vars": """  var numProcesso = getValue("WKNumProces");
  log.info("afterProcessFinish - processo: " + numProcesso);
""",
                "body": """  // Logica apos finalizacao do processo
  // Ex: integrar com sistema externo, enviar email, etc.
""",
            },
            "subProcessCreated": {
                "sig": "function subProcessCreated(colleagueId)",
                "vars": """  var numProcesso = getValue("WKNumProces");
  log.info("subProcessCreated - processo: " + numProcesso);
""",
                "body": """  // Logica apos criacao de sub-processo
""",
            },
        }

        evento = assinaturas.get(nome_evento)
        if not evento:
            nomes = ", ".join(sorted(assinaturas.keys()))
            return f"Evento '{nome_evento}' nao reconhecido. Eventos suportados: {nomes}"

        return f"""/**
 * Evento: {nome_evento}
 * Processo: <nome do processo>
 * Logica: {descricao_logica}
 */
{evento["sig"]} {{
{evento["vars"]}
  try {{
    // TODO: {descricao_logica}

{evento["body"]}
  }} catch (e) {{
    log.error("Erro em {nome_evento}: " + e.getMessage());
    throw e;
  }}
}}
"""

    @mcp.tool()
    def fluig_scaffold_evento_form(
        nome_evento: str,
        descricao_logica: str,
    ) -> str:
        """
        Gera evento de formulario com assinatura correta (server-side ou client-side)
        alinhado com as convencoes dos skills Fluig.

        Args:
            nome_evento: Nome do evento. Suportados:
                'inputFields', 'beforeSendValidate', 'afterSaveNew', 'afterSaveUpdate',
                'validateForm', 'displayFields', 'enableFields'.
            descricao_logica: O que o evento deve fazer.
        """
        eventos = {
            "inputFields": {
                "sig": "function inputFields(form, customHTML)",
                "tipo": "server-side",
                "body": f"""  // Transformacao de dados server-side antes de exibir o formulario
  // TODO: {descricao_logica}

  // Exemplo: preencher campo com data atual
  // form.setValue("data_criacao", new java.text.SimpleDateFormat("dd/MM/yyyy").format(new java.util.Date()));
""",
            },
            "beforeSendValidate": {
                "sig": "function beforeSendValidate(numState, mobileRequest)",
                "tipo": "client-side",
                "body": f"""  // Validacao client-side antes de enviar — numState indica a atividade atual
  // TODO: {descricao_logica}

  if (numState !== 0) {{ // Ignora rascunho
    var campo = $("#campo_obrigatorio").val();
    if (!campo || campo.trim() === "") {{
      FLUIGC.toast({{
        title: "Validacao",
        message: "Preencha o campo obrigatorio.",
        type: "warning"
      }});
      throw "Validacao: campo obrigatorio vazio.";
    }}
  }}
""",
            },
            "afterSaveNew": {
                "sig": "function afterSaveNew(form)",
                "tipo": "server-side",
                "body": f"""  // Executado apos salvar novo registro (primeira vez)
  // TODO: {descricao_logica}

  // Exemplo: integracao pos-save
  // var codigo = form.getValue("codigo");
  // log.info("Novo registro salvo: " + codigo);
""",
            },
            "afterSaveUpdate": {
                "sig": "function afterSaveUpdate(form)",
                "tipo": "server-side",
                "body": f"""  // Executado apos atualizar registro existente
  // TODO: {descricao_logica}

  // Exemplo: log de atualizacao
  // var codigo = form.getValue("codigo");
  // log.info("Registro atualizado: " + codigo);
""",
            },
            "validateForm": {
                "sig": "function validateForm(form)",
                "tipo": "server-side",
                "body": f"""  // Validacao server-side — throw para bloquear
  // TODO: {descricao_logica}

  var campo = form.getValue("campo_obrigatorio");
  if (!campo || campo.trim() === "") {{
    throw "Campo obrigatorio nao preenchido.";
  }}
""",
            },
            "displayFields": {
                "sig": "function displayFields(form, customHTML, currentState)",
                "tipo": "client-side",
                "body": f"""  // Controle de visibilidade de campos por atividade (state)
  // TODO: {descricao_logica}

  // Exemplo: ocultar campos em determinada atividade
  // if (currentState === "2") {{
  //   customHTML.append("<style>#campo_interno {{ display: none; }}</style>");
  // }}
""",
            },
            "enableFields": {
                "sig": "function enableFields(form, customHTML, currentState)",
                "tipo": "client-side",
                "body": f"""  // Controle de habilitacao de campos por atividade (state)
  // TODO: {descricao_logica}

  // Exemplo: desabilitar campos em atividade de aprovacao
  // if (currentState === "3") {{
  //   $("input, select, textarea").prop("disabled", true);
  //   $("#campo_aprovacao").prop("disabled", false);
  // }}
""",
            },
        }

        evento = eventos.get(nome_evento)
        if not evento:
            nomes = ", ".join(sorted(eventos.keys()))
            return f"Evento '{nome_evento}' nao reconhecido. Eventos suportados: {nomes}"

        return f"""/**
 * Evento de Formulario: {nome_evento} ({evento["tipo"]})
 * Logica: {descricao_logica}
 */
{evento["sig"]} {{
{evento["body"]}}}
"""

    @mcp.tool()
    def fluig_scaffold_rest_call(
        url: str,
        metodo: str = "GET",
        descricao: str = "",
        sincrono: bool = False,
    ) -> str:
        """
        Gera chamada REST correta para uso dentro de um widget Fluig (this.rest / this.restSync).

        Args:
            url: Endpoint relativo. Ex: '/api/public/ecm/dataset/search'.
            metodo: Metodo HTTP. 'GET' ou 'POST'.
            descricao: O que a chamada faz.
            sincrono: Se true, gera this.restSync (sincrono). Padrao false (assincrono).
        """
        if sincrono:
            return f"""// Chamada REST sincrona — {descricao}
// ATENCAO: restSync bloqueia o browser ate retornar. Usar com moderacao.
var resultado = this.restSync({{
  type: "{metodo.upper()}",
  url: WCMAPI.getServerURL() + "{url}",
  {"data: JSON.stringify(payload)," if metodo.upper() == "POST" else ""}
  contentType: "application/json"
}});

if (resultado) {{
  var dados = JSON.parse(resultado);
  // processar dados aqui
}}
"""
        corpo_data = ""
        if metodo.upper() == "POST":
            corpo_data = """  // data: JSON.stringify(payload),  // descomente e defina payload
  contentType: "application/json","""

        return f"""// Chamada REST assincrona — {descricao}
this.rest({{
  type: "{metodo.upper()}",
  url: WCMAPI.getServerURL() + "{url}",
{corpo_data}
  success: function(data) {{
    // TODO: processar resposta
    console.log("Resposta:", data);
  }},
  error: function(xhr, status, error) {{
    console.error("Erro na chamada REST ({url}):", error);
    console.error("Status:", xhr.status, xhr.responseText);
  }}
}});
"""

    @mcp.tool()
    def fluig_scaffold_mustache(
        nome_template: str,
        campos: str,
    ) -> str:
        """
        Gera template Mustache para renderizacao de dados em widget Fluig.

        Args:
            nome_template: ID do template. Ex: 'lista-colaboradores'.
            campos: JSON string com campos a exibir. Ex: '["nome","departamento","email"]'.
        """
        try:
            lista_campos = json.loads(campos)
        except json.JSONDecodeError:
            return "Erro: 'campos' deve ser um JSON array. Ex: [\"campo1\",\"campo2\"]"

        linhas_campos = "\n    ".join([
            f'<div class="col-sm-6 col-xs-12"><strong>{html.escape(c)}:</strong> {{{{{{{{ {c} }}}}}}}}</div>'
            for c in lista_campos
        ])

        return f"""<!-- Template Mustache: {html.escape(nome_template)} -->
<!-- Inserir no view.ftl dentro de uma tag script type="text/html" -->
<script type="text/html" id="{html.escape(nome_template)}-template">
  {{{{{{{{#itens}}}}}}}}
  <div class="row item-row" style="border-bottom:1px solid #eee; padding:8px 0;">
    {linhas_campos}
  </div>
  {{{{{{{{/itens}}}}}}}}
  {{{{{{{{^itens}}}}}}}}
  <div class="alert alert-info">
    Nenhum item encontrado.
  </div>
  {{{{{{{{/itens}}}}}}}}
</script>

<!-- Uso no JS do widget: -->
<!-- var html = Mustache.to_html($("#{html.escape(nome_template)}-template").html(), {{ itens: dados }}); -->
<!-- $("#container").html(html); -->
"""


# --- helpers ---

def _camel(texto: str) -> str:
    partes = texto.replace("-", " ").replace("_", " ").split()
    return "".join(p.capitalize() for p in partes)


def _kebab(texto: str) -> str:
    return texto.lower().replace(" ", "-").replace("_", "-")


def _gerar_campos(lista_campos: list) -> list:
    htmls = []
    for campo in lista_campos:
        nome = html.escape(campo.get("nome", "campo"))
        label = html.escape(campo.get("label", campo.get("nome", "campo")))
        tipo = campo.get("tipo", "text")
        obrig = campo.get("obrigatorio", False)
        col = campo.get("col", "6")
        obrig_mark = ' <span class="text-danger">*</span>' if obrig else ""
        obrig_attr = " required" if obrig else ""

        col_class = f"col-sm-{col} col-xs-12"

        if tipo == "textarea":
            htmls.append(f"""
        <div class="{col_class}">
          <div class="form-group">
            <label for="{nome}">{label}{obrig_mark}</label>
            <textarea class="form-control" id="{nome}" name="{nome}" rows="3"{obrig_attr}></textarea>
          </div>
        </div>""")
        elif tipo == "select":
            opcoes = campo.get("opcoes", [])
            opts_html = "\n            ".join([f'<option value="{html.escape(o)}">{html.escape(o)}</option>' for o in opcoes])
            htmls.append(f"""
        <div class="{col_class}">
          <div class="form-group">
            <label for="{nome}">{label}{obrig_mark}</label>
            <select class="form-control" id="{nome}" name="{nome}"{obrig_attr}>
              <option value="">Selecione...</option>
              {opts_html}
            </select>
          </div>
        </div>""")
        elif tipo == "date":
            htmls.append(f"""
        <div class="{col_class}">
          <div class="form-group">
            <label for="{nome}">{label}{obrig_mark}</label>
            <div class="input-group date" id="{nome}_picker">
              <input type="text" class="form-control" id="{nome}" name="{nome}"{obrig_attr} />
              <span class="input-group-addon"><i class="fluigicon fluigicon-calendar"></i></span>
            </div>
          </div>
        </div>""")
        elif tipo == "checkbox":
            htmls.append(f"""
        <div class="{col_class}">
          <div class="checkbox">
            <label>
              <input type="checkbox" id="{nome}" name="{nome}" value="true" />
              {label}
            </label>
          </div>
        </div>""")
        elif tipo == "radio":
            opcoes = campo.get("opcoes", ["Opcao 1", "Opcao 2"])
            radios = "\n          ".join([
                f'<div class="radio"><label><input type="radio" name="{nome}" value="{html.escape(o)}" /> {html.escape(o)}</label></div>'
                for o in opcoes
            ])
            htmls.append(f"""
        <div class="{col_class}">
          <div class="form-group">
            <label>{label}{obrig_mark}</label>
            {radios}
          </div>
        </div>""")
        elif tipo == "autocomplete":
            dataset = html.escape(campo.get("dataset", "ColleagueDS"))
            campo_ret = html.escape(campo.get("campo_retorno", "colleagueName"))
            htmls.append(f"""
        <div class="{col_class}">
          <div class="form-group">
            <label for="{nome}">{label}{obrig_mark}</label>
            <input type="text" class="form-control" id="{nome}" name="{nome}"
              data-toggle="fluig-lookup"
              data-dataset="{dataset}"
              data-field="{campo_ret}"
              data-display-field="{campo_ret}"{obrig_attr} />
          </div>
        </div>""")
        else:
            htmls.append(f"""
        <div class="{col_class}">
          <div class="form-group">
            <label for="{nome}">{label}{obrig_mark}</label>
            <input type="text" class="form-control" id="{nome}" name="{nome}"{obrig_attr} />
          </div>
        </div>""")
    return htmls


def _gerar_anexo() -> str:
    return """
      <div class="row">
        <div class="col-sm-12 col-xs-12">
          <div class="form-group">
            <label>Anexos</label>
            <div data-attachments="true"
                 data-process-id="${process.processId}"
                 data-instance-id="${process.processInstanceId}"
                 data-allow-multiple="true">
            </div>
          </div>
        </div>
      </div>"""


def _gerar_abas(campos_html: list, lista_campos: list) -> str:
    metade = len(campos_html) // 2 or 1
    aba1 = "".join(campos_html[:metade])
    aba2 = "".join(campos_html[metade:])
    return f"""
  <!-- Painel fixo: Dados da Solicitacao (sempre visivel acima das abas) -->
  <div class="panel panel-default">
    <div class="panel-heading">
      <h3 class="panel-title">Dados da Solicitacao</h3>
    </div>
    <div class="panel-body">
      <p class="text-muted">Campos fixos desta solicitacao.</p>
    </div>
  </div>

  <ul class="nav nav-tabs" id="formTabs">
    <li class="active"><a href="#aba-dados" data-toggle="tab">Dados</a></li>
    <li><a href="#aba-complemento" data-toggle="tab">Complemento</a></li>
  </ul>
  <div class="tab-content" style="padding-top:16px">
    <div class="tab-pane active" id="aba-dados">
      <div class="row">{aba1}</div>
    </div>
    <div class="tab-pane" id="aba-complemento">
      <div class="row">{aba2}</div>
    </div>
  </div>"""
