@extends('layouts.app')
@section('title') Lists @endsection
@section('content')
  <!-- Notification -->
  <div x-data="notification()" x-init="init(); notification_success = true">
    <div
      x-cloak
      x-show="isVisible"
      x-transition:enter="transition ease-out duration-300"
      x-transition:enter-start="opacity-0 transform translate-y-2"
      x-transition:enter-end="opacity-100 transform translate-y-0"
      x-transition:leave="transition ease-in duration-200"
      x-transition:leave-start="opacity-100 transform translate-y-0"
      x-transition:leave-end="opacity-0 transform translate-y-2"
      class="fixed inset-x-0 top-3 z-20 flex items-center justify-center px-4 py-6 pointer-events-none sm:p-6 sm:items-start sm:justify-center"
    >
      <div :class="notification_success ? 'bg-green-600' : 'bg-red-600'" class="max-w-sm w-full shadow-lg text-white rounded-lg pointer-events-auto">
        <div class="p-4">
          <p class="text-sm text-center" x-text="message"></p>
        </div>
      </div>
    </div>
  </div>
  <!-- Notification -->
<div x-data="{show_info: false}" class="flex gap-3 flex-col my-4 animate-slide-up-fade-in">
  <div class="flex-1 justify-between h-fit border-2 border-cyan-700 dark:border-cyan-200 flex-col bg-white dark:bg-slate-900  rounded-lg shadow-md p-4 hover:shadow-lg hover:transition-all">
    <div class="cursor-pointer" x-on:click="show_info = !show_info">
      <span class="text-lg inline-flex items-center">
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 mr-2 dark:stroke-cyan-200 stroke-cyan-700">
          <path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" />
        </svg>
        Info
      </span>
    </div>
    <div x-cloak x-show="show_info" class="animate-slide-down-fade-in">
      <p>We have developed a <strong>"list"</strong> feature designed to streamline the creation and management of various types of lists essential for server security and email management.
        <br/>These lists can include:
      </p>
      <ul class="list-inside list-disc my-2">
        <li><strong>Whitelist Emails</strong>: Approved email addresses allowed through filters.</li>
        <li><strong>Blacklist Emails</strong>: Blocked email addresses.</li>
        <li><strong>IP Whitelists</strong>: Approved IP addresses granted access.</li>
        <li><strong>IP Blacklists</strong>: Blocked IP addresses.</li>
        <li><strong>URIBL Databases</strong>: Lists of domains either allowed (whitelist) or blocked (blacklist).</li>
      </ul>
      <p>After creating a list and inserting elements to it, you can retrieve it with regular HTTP requests:</p>
      <pre class="bg-black text-gray-200 p-2 my-2 border border-white rounded-md overflow-x-auto">
<code class="font-mono text-sm">$ curl -s {{ route("get_list", ["15ac518c-100f-4bc6-8e83-2d78f09c6ffd", "json"]) }} | jq
[
  "192.168.1.1",
  "10.10.1.1"
]

$ wget -O /etc/csf/csf_personal.allow {{ route("get_list", ["15ac518c-100f-4bc6-8e83-2d78f09c6ffd", "raw"]) }}</code>
</pre>
      <div class="border-s-2 border-orange-300 rounded-md dark:bg-orange-200/10 bg-orange-200/50">
        <h3 class="w-fit p-3 text-lg">List visibility warning</h3>
        <p class="p-3">Although a list is protected by its own URL which contains a <abbr title="Universal Unique ID">UUID</abbr>, there is no other <abbr title="Access-Control List">ACL</abbr> in place.<br/>
          If you share a list's URL you can't revoke access to it unless you entirely delete the list.
        </p>
      </div>
    </div>
  </div>
</div>
<div class="flex gap-3 flex-col my-4 items-center animate-slide-up-fade-in">
  <div class="flex-1 justify-between h-fit w-fit border-s-2 border-indigo-400 flex-col bg-white dark:bg-slate-900  rounded-lg shadow-md p-4 hover:shadow-lg hover:transition-all">
    <div class="">
    <span class="text-lg inline-flex items-center">
      <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 mr-2">
        <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v6m3-3H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
      </svg>
      Create a new list
    </span>
    </div>
    <span class="text-xs mb-3">Use this form to create a new list and add elements to it.</span>
    <div class="flex flex-col gap-3">
      <div>
        <input class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg block w-full p-2.5  mt-2 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white" id="list_name" type="text" name="list_name" placeholder="List name">
      </div>
      <div>
      <button onclick="create_list()" id="btn_create_list" class="px-4 w-full py-2 text-m font-medium text-gray-900 bg-white border border-gray-200 rounded-lg hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:text-white dark:hover:bg-gray-700">Create</button>
      </div>
    </div>
  </div>
</div>
<div>
  <div id="lists_div" class="grid lg:grid-cols-3 gap-3  my-4 ">
  </div>
</div>

<script>

const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
  document.addEventListener('DOMContentLoaded', function () {
    document.getElementById('menu_lists').classList.remove('text-gray-500');
    document.getElementById('menu_lists').classList.remove('hover:bg-gray-700');
    document.getElementById('menu_lists').classList.remove('hover:bg-opacity-25');
    document.getElementById('menu_lists').classList.remove('hover:text-gray-100');
    document.getElementById('menu_lists').classList.add('text-gray-100');
    document.getElementById('menu_lists').classList.add('bg-opacity-25');
    document.getElementById('menu_lists').classList.add('bg-gray-700');
    document.getElementById('menu_lists').classList.add('border-e-2');
    document.getElementById('menu_lists').classList.add('border-indigo-400');

  // Load lists with AJAX
  fetch('{{ route("load_lists") }}',{
        method: "GET",
        headers: {
        'X-CSRF-TOKEN': csrfToken,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        },
      })
      .then( response =>
      {
        return response.json();
      })
      .then( response => 
      {
        response.forEach( (list) =>
        {
          load_list(list.id);
        });
      });
  });
  window.datatables_list = {};
  function notification() {
    return {
      isVisible: false,
      notification_status: true,
      message: '',
      init() {
        window.showNotification = this.show.bind(this);
      },
      show(msg, status) {
        this.message = msg;
        this.notification_success = status;
        this.isVisible = true;
        delay = status ? 3000 : 6000;
        setTimeout(() => {
          this.isVisible = false;
        }, delay);
      }
    }
  }

 async function create_list()
  {
    list_name = document.getElementById("list_name").value;
    if (list_name == '')
    {
      showNotification('List name cannot be empty.', false)
      return;
    }
    await fetch('{{ route("create_list") }}',{
        method: "POST",
        headers: {
        'X-CSRF-TOKEN': csrfToken,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        },
        body : JSON.stringify({name:list_name}),
      })
      .then( response =>
      {
        return response.json();
      })
      .then(response =>
      {
        if ( response.code === 0 )
        {
          showNotification('List created successfully!', true);
          load_list(response.list.id);
        }
      }
      );
  }
async function load_list(id)
{

  await fetch("{{ route('fetch_list_data') }}",{
    method: "POST",
    headers: {
    'X-CSRF-TOKEN': csrfToken,
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    },
    body : JSON.stringify({"list_id": id, "all_data": true}),
  })
  .then( response =>
  {
    return response.json();
  })
  .then(response =>
  {
    if ( response.code === 0 )
    {
      render_list(response);
    }
    else
    {
      showNotification(`${response.message}`,false);
    }
  }
  );
  
}

  function render_list ( list )
  {
    var list_html =
`<div id="list_${list.list.id}" class="flex-1 animate-slide-up-fade-in h-fit w-full border-s-2 border-indigo-400 flex-col bg-white dark:bg-slate-900  rounded-lg shadow-md p-4 hover:shadow-lg hover:transition-all">
  <div class="text-center mb-2">
    <span class="text-lg font-semibold">${list.list.name}</span>
  </div>
  <div class="items-center text-center" x-data="{open: false}">
    <div class="inline-flex items-center">
      <button type="button" class="px-2 py-1 text-xs text-gray-900 bg-white border-s border-y border-gray-200 rounded-s-md dark:bg-gray-800 dark:border-gray-700 dark:text-white btn_copy" data-url="${list.url_raw}"> Copy URL</button>
      <button x-on:click.away="open=false" x-on:click="open=!open;" type="button" class="px-2 py-1 text-xs text-gray-900 bg-white border border-gray-200 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:text-white dark:hover:bg-gray-700 dropdown-toggle dropdown-icon" data-toggle="dropdown" aria-expanded="false">
      ...
      </button>
      <div x-cloak x-show="open" class="animate-slide-down-fade-in absolute z-10 mt-16 p-2 bg-white border-gray-200 dark:border-gray-700 dark:bg-gray-800 border rounded-lg inline-flex shadow-md" role="menu" style="">
        <button class="px-2 py-1 text-xs text-gray-900 bg-white border border-gray-200 rounded-s-md dark:bg-gray-800 dark:border-gray-700 dark:text-white btn_copy  btn_copy_raw" href="#" data-url="${list.url_raw}">Raw Format</button>
        <button class="px-2 py-1 text-xs text-gray-900 bg-white border-e border-y border-gray-200 rounded-e-md dark:bg-gray-800 dark:border-gray-700 dark:text-white btn_copy btn_copy_json" href="#" data-url="${list.url_json}">JSON Format</button>
      </div>
      <button class="px-2 py-1 text-xs text-gray-900 bg-red-300 border-y border-e border-red-300 rounded-e-md dark:bg-red-500 dark:border-red-500 dark:text-white btn_delete_list" data-list_id="${list.list.id}">Delete</button>
    </div>
  </div>
  <div class="mt-2 grid gap-2 items-center">
    <div>
      <textarea class="w-full h-20 border border-slate-700 dark:border-slate-200 dark:bg-slate-700 p-3 font-mono text-xs rounded-md" placeholder="One element per line. e.g.:\n1.2.3.4\n4.3.2.1"></textarea>
    </div>
    <div class="items-center text-center">
      <button class="px-2 py-1 text-sm text-gray-900 bg-white border border-gray-200 rounded-md dark:bg-gray-800 dark:border-gray-700 dark:text-white btn_add_to_list" data-list_id="${list.list.id}">Add to list</button>
    </div>
  </div>
  <div class="card-body">
    <table class="table-auto w-full overflow-x-auto report_table" id="table_list_id_${list.list.id}">
      <thead>
        <tr>
          <th></th>
          <th>Data</th>
        </tr>
      </thead>
      <tbody>
      </tbody>
    </table>
  </div>
</div>`;
    lists = document.getElementById("lists_div");
    lists.insertAdjacentHTML("beforeend", list_html);
    load_list_data(list.list.id, list.list_data);
  }

  function load_list_data ( list_id, data )
  {
    var tbl = new DataTable("#table_list_id_"+list_id,
    {
      perPage: 10,
      perPageSelect: [10, 100, 200, 500, ["All", 0]],
      labels: {
        placeholder: "Filter data..."
      },
      rowRender: (row, tr, _index) => {
          tr.attributes.class = "hover:bg-slate-200 dark:hover:bg-slate-700";
          if (tr.childNodes) {
            tr.childNodes.forEach(td => {
              td.attributes.class = "border-b border-slate-200 dark:border-slate-600 p-1 text-slate-900 dark:text-slate-400 text-sm text-center";
            });
          }
        },
        data: {
          headings: [
            {
              text: 'Delete',
              data: 'delete'
            },
            {
              text: 'Data',
              data: 'data',
            }
          ],
        },
        columns: [
          {
            select: 0,
            type: "other",
            data: 'delete',
            render: (data) => {
              return `<button onclick="delete_list_data(this)" class="px-2 py-1 text-xs text-gray-900 bg-white border border-gray-200 rounded-md hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:text-white dark:hover:bg-gray-700 btn_delete_data" data-list_id="${data.id}" data-list_data="${data.data}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4 fill-red-400">
  <path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM8.28 7.22a.75.75 0 0 0-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 1 0 1.06 1.06L10 11.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L11.06 10l1.72-1.72a.75.75 0 0 0-1.06-1.06L10 8.94 8.28 7.22Z" clip-rule="evenodd" />
</svg>
</button>`;
            }
          },
          {
            select: 1,
            type: "string",
            data: 'data',
          },
        ]
    });
    var tbl_data = [];

    data.forEach( row =>
    {
      tbl_data.push({delete:{data: row.data, id:row.list_id},data:row.data});
    });
    tbl.insert(tbl_data);
    window.datatables_list[list_id] = tbl;
  }

  document.addEventListener('click', function(event) {
  if (event.target.matches('.btn_copy, .btn_copy_raw, .btn_copy_json')) {
    var copy_url = event.target.dataset.url;
    try
    {
      navigator.clipboard.writeText(copy_url);
      showNotification("List URL copied", true);
    }
    catch (error)
    {
      alert(error);
    }
  }

  if (event.target.matches('.btn_add_to_list')) {
    var data = event.target.parentElement.parentElement.querySelector("textarea").value;
    var list_id = event.target.dataset.list_id;
    if ( data != "" )
    {
      // Send request
      fetch("{{ route('add_data_to_list') }}",{
        method: "POST",
        headers: {
        'X-CSRF-TOKEN': csrfToken,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        },
        body : JSON.stringify({data:data,list_id:list_id})
      })
      .then(response =>
      {
        return response.json();
      })
      .then(response =>
      {
        showNotification(`Total items inserted ${response.count}`, true);
        
        tbl_data = []
        response.saved_elements.forEach( row => {
          tbl_data.push({delete:{data: row, id:list_id},data:row});
        });
        tbl = window.datatables_list[list_id];
        tbl.insert(tbl_data);
      })  
      event.target.parentElement.parentElement.querySelector("textarea").value = "";
    }
    else
    {
      // Textbox empty, show message.
      showNotification("Can't send empty data.", false);
    }
  }

  if (event.target.matches('.btn_delete_list')) {
    var list_id = event.target.dataset.list_id;
    fetch("{{ route('delete_list') }}",{
        method: "POST",
        headers: {
        'X-CSRF-TOKEN': csrfToken,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        },
        body : JSON.stringify({list_id:list_id})
      })
      .then(response =>
      {
        return response.json();
      })
      .then(response =>
      {
        if ( response.code === 0 )
        {
          showNotification(`List deleted.`, true);
          document.getElementById(`list_${list_id}`).remove();
        }
        else
        {
          showNotification(`List could not be deleted: ${response.message}.`, false);
        }

      })  
  }

});


function delete_list_data(button)
{

  var list_id = button.dataset.list_id;
  var data = button.dataset.list_data;
  
  fetch("{{ route('delete_data_from_list') }}",{
      method: "POST",
      headers: {
      'X-CSRF-TOKEN': csrfToken,
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      },
      body : JSON.stringify({data:data, list_id:list_id})
    })
    .then(response =>
    {
      return response.json();
    })
    .then(response =>
    {
      showNotification(`List data deleted.`, true);

      const tbl = window.datatables_list[list_id];
      data_index = button.closest("tr").dataset.index;
      tbl.rows.remove(parseInt(data_index));
    })  
}
</script>

@endsection
