
from datetime import datetime
from json import dumps
from secrets import choice
from string import ascii_letters, digits

from core import output
from core.config import CONFIG

from oci.config import validate_config
from oci.exceptions import ServiceError
from oci.auth.signers import InstancePrincipalsSecurityTokenSigner
from oci.loggingingestion import LoggingClient
from oci.loggingingestion.models import LogEntry, LogEntryBatch, PutLogsDetails

from twisted.python.log import err


class Output(output.Output):
    """
    Oracle Cloud output
    """

    def generate_random_log_id(self):
        charset = ascii_letters + digits
        random_log_id = ''.join(choice(charset) for _ in range(32))
        return 'mssqlpotlog-{}'.format(random_log_id)

    def sendLogs(self, event):
        log_id = self.generate_random_log_id()
        # Initialize service client with default config file
        current_time = datetime.utcnow()
        self.log_ocid = CONFIG.get('output_oraclecloud', 'log_ocid')
        self.hostname = CONFIG.get('honeypot', 'hostname')

        try:
            # Send the request to service, some parameters are not required, see API
            # doc for more info
            self.loggingingestion_client.put_logs(
                log_id=self.log_ocid,
                put_logs_details=PutLogsDetails(
                    specversion='1.0',
                    log_entry_batches=[
                        LogEntryBatch(
                            entries=[
                                LogEntry(
                                    data=event,
                                    id=log_id,
                                    time=current_time.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
                                )
                            ],
                            source=self.hostname,
                            type='mssqlpot',
                        )
                    ],
                ),
                timestamp_opc_agent_processing=current_time.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
            )
        except ServiceError as ex:
            err(
                ('Oracle Cloud plugin Error: {}\n'
                'Oracle Cloud plugin Status Code: {}\n').format(ex.message, ex.status)
            )
        except Exception as ex:
            err('Oracle Cloud plugin Error: {}'.format(ex))
            raise

    def start(self):
        """
        Initialize Oracle Cloud LoggingClient with user or instance principal authentication
        """
        authtype = CONFIG.get('output_oraclecloud', 'authtype')

        if authtype == 'instance_principals':
            signer = InstancePrincipalsSecurityTokenSigner()

            # In the base case, configuration does not need to be provided as the region and
            # tenancy are obtained from the InstancePrincipalsSecurityTokenSigner
            # identity_client = oci.identity.IdentityClient(config={}, signer=signer)
            self.loggingingestion_client = LoggingClient(config={}, signer=signer)

        elif authtype == 'user_principals':
            tenancy_ocid = CONFIG.get('output_oraclecloud', 'tenancy_ocid')
            user_ocid = CONFIG.get('output_oraclecloud', 'user_ocid')
            region = CONFIG.get('output_oraclecloud', 'region')
            fingerprint = CONFIG.get('output_oraclecloud', 'fingerprint')
            keyfile = CONFIG.get('output_oraclecloud', 'keyfile')

            config_with_key_content = {
                'user': user_ocid,
                'key_file': keyfile,
                'fingerprint': fingerprint,
                'tenancy': tenancy_ocid,
                'region': region,
            }
            validate_config(config_with_key_content)
            self.loggingingestion_client = LoggingClient(
                config_with_key_content
            )
        else:
            raise ValueError('Invalid authentication type')

    def stop(self):
        pass

    def write(self, event):
        """
        Push to Oracle Cloud put_logs
        """
        self.sendLogs(dumps(event))
