"""
Copyright(C) 2018-2021 Chris Hansen <hansec@uw.edu>
Copyright(C) 2021-2025 Stamus Networks SAS
Written by Chris Hansen <hansec@uw.edu>
Written by Eric Leblond <eld@stamus-networks.com>

This file is part of Suricata Language Server.

Suricata Language Server is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Suricata Language Server is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Suricata Language Server.  If not, see <http://www.gnu.org/licenses/>.
"""

import sys
import argparse
from suricatals.langserver import LangServer
from suricatals.suricata_command import SuriCmd
from suricatals.suricata_discovery import SuricataDiscovery
import json
from importlib.metadata import version


__version__ = version("suricata-language-server")


def error_exit(error_str):
    print("ERROR: {0}".format(error_str))
    sys.exit(-1)


def main():
    #
    parser = argparse.ArgumentParser()
    parser.description = "Suricata Language Server ({0})".format(__version__)
    parser.add_argument(
        "--version", action="store_true", help="Print server version number and exit"
    )
    parser.add_argument(
        "--container",
        action="store_true",
        default=False,
        help="Use a container to run Suricata",
    )
    parser.add_argument(
        "--image",
        default=SuriCmd.SLS_DEFAULT_DOCKER_IMAGE,
        help="Suricata image to use in container mode",
    )
    parser.add_argument(
        "--suricata-binary", default="suricata", help="Path to Suricata binary"
    )
    parser.add_argument(
        "--suricata-config", default=None, help="Path to Suricata config"
    )
    parser.add_argument(
        "--debug-log",
        action="store_true",
        help="Generate debug log in project root folder",
    )
    parser.add_argument(
        "--max-lines",
        default=1000,
        type=int,
        help="Don't start suricata analysis over this file size",
    )
    parser.add_argument(
        "--max-tracked-files",
        default=100,
        type=int,
        help="Don't start suricata analysis if workspace file count is superior to this limit",
    )
    parser.add_argument(
        "--batch-file",
        default=None,
        help="Batch mode to parse only the file in argument",
    )
    parser.add_argument(
        "--no-engine-analysis",
        action="store_true",
        default=False,
        help="Disable suricata engine analysis (used with --batch-file only)",
    )
    parser.add_argument(
        "--error-on-warning",
        action="store_true",
        default=False,
        help="Exit with code 1 if there are any warnings (used with --batch-file only)",
    )
    parser.add_argument(
        "--idle-timeout",
        default=3.0,
        type=float,
        help="Seconds of inactivity before auto-analyzing open buffer (default: 3.0, 0 to disable)",
    )
    parser.add_argument(
        "--list-keywords",
        action="store_true",
        default=False,
        help="List all Suricata keywords in CSV format and exit",
    )
    parser.add_argument(
        "--list-app-layer-protos",
        action="store_true",
        default=False,
        help="List all Suricata app-layer protocols and exit",
    )
    args = parser.parse_args()
    if args.version:
        print("{0}".format(__version__))
        sys.exit(0)
    if args.list_keywords:
        suricmd = SuriCmd(
            suricata_binary=args.suricata_binary, suricata_config=args.suricata_config
        )
        if args.container:
            suricmd.set_docker_mode(docker_image=args.image)
        discovery = SuricataDiscovery(suricmd)
        outdata = discovery.get_keywords_csv()
        if outdata:
            print(outdata)
            sys.exit(0)
        else:
            error_exit("Failed to retrieve keywords list")
    if args.list_app_layer_protos:
        suricmd = SuriCmd(
            suricata_binary=args.suricata_binary, suricata_config=args.suricata_config
        )
        if args.container:
            suricmd.set_docker_mode(docker_image=args.image)
        discovery = SuricataDiscovery(suricmd)
        outdata = discovery.get_app_layer_protos_list()
        if outdata:
            print(outdata)
            sys.exit(0)
        else:
            error_exit("Failed to retrieve app-layer protocols list")
    #
    settings = {
        "suricata_binary": args.suricata_binary,
        "suricata_config": args.suricata_config,
        "docker_mode": args.container,
        "docker_image": args.image,
        "max_lines": args.max_lines,
        "max_tracked_files": args.max_tracked_files,
        "idle_timeout": args.idle_timeout,
    }
    #
    if not args.batch_file and args.no_engine_analysis:
        print("--no-engine-analysis must be used with --batch-file")

    if args.batch_file is None:
        s = LangServer(
            debug_log=args.debug_log,
            settings=settings,
        )
        s.run()
    else:
        s = LangServer(settings=settings, batch_mode=True)
        _, _, diags = s.analyse_file(args.batch_file, not args.no_engine_analysis)
        exit_code = 0
        for diag in diags:
            print(json.dumps(diag.to_message()))
            severity = diag.severity.value
            if severity == 1:
                exit_code = 1
            elif args.error_on_warning and severity == 2 and exit_code == 0:
                exit_code = 1
        sys.exit(exit_code)
