#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#
import logging

from gremlin_python.driver.remote_connection import RemoteConnection, RemoteTraversal

log = logging.getLogger("gremlinpython")


class Transaction:
    """Controls an explicit remote transaction. A thin wrapper around a Client
    that adds transaction lifecycle (begin/commit/rollback/close) and attaches
    a transactionId to every request.

    Created via Client.transact() or g.tx(). The traversal source (g alias)
    is inherited from the Client and cannot be changed.

    Transactions are short-lived and single-use. After commit or rollback,
    the transaction ID is invalid and the object cannot be reused.

    This class is NOT thread-safe.
    """

    def __init__(self, client):
        self._client = client
        self._transaction_id = None
        self._is_open = False
        self._failed = False

    def begin(self):
        """Starts the transaction and returns a transaction-bound GraphTraversalSource.

        The returned GTS can be used to submit traversals within this transaction.
        Users of the driver-level API (client.transact()) may ignore the return
        value and use submit() directly instead.
        """
        if self._is_open or self._failed:
            raise Exception("Transaction already started")

        try:
            result = self._client.submit("g.tx().begin()")
            results = result.all().result()
        except Exception:
            self._failed = True
            raise

        if not results:
            self._failed = True
            raise Exception("Server did not return transaction ID")

        result_map = results[0]
        if isinstance(result_map, dict):
            self._transaction_id = result_map.get('transactionId')
        else:
            self._failed = True
            raise Exception("Server did not return transaction ID in expected format")

        if not self._transaction_id:
            self._failed = True
            raise Exception("Server returned empty transaction ID")

        self._is_open = True
        self._client.track_transaction(self)

        # Return a GraphTraversalSource bound to this transaction via
        # TransactionRemoteConnection. Inline imports avoid circular dependencies
        # between driver/ and process/ packages.
        from gremlin_python.process.graph_traversal import GraphTraversalSource
        from gremlin_python.process.traversal import TraversalStrategies, GremlinLang
        from gremlin_python.driver.remote_connection import RemoteStrategy

        tx_connection = TransactionRemoteConnection(self)
        strategies = TraversalStrategies()
        strategies.add_strategies([RemoteStrategy(tx_connection)])
        return GraphTraversalSource(None, strategies, GremlinLang())

    def submit(self, gremlin, bindings=None, request_options=None):
        """Submits a gremlin-lang string within this transaction.

        The transactionId is automatically attached. Has the same signature
        as Client.submit() so both can be used interchangeably.
        """
        if not self._is_open:
            raise Exception("Transaction is not open")
        opts = {'transactionId': self._transaction_id}
        if request_options:
            opts.update(request_options)
        return self._client.submit(gremlin, bindings=bindings, request_options=opts)

    def commit(self):
        """Commits the transaction."""
        self._close_transaction("g.tx().commit()")

    def rollback(self):
        """Rolls back the transaction."""
        self._close_transaction("g.tx().rollback()")

    def _close_transaction(self, script):
        if not self._is_open:
            raise Exception("Transaction is not open")
        self._client.submit(script, request_options={'transactionId': self._transaction_id}).all().result()
        self._is_open = False
        self._failed = True  # Terminal state: transaction cannot be reused
        self._client.untrack_transaction(self)

    @property
    def is_open(self):
        return self._is_open

    @property
    def transaction_id(self):
        return self._transaction_id

    def close(self):
        if self._is_open:
            self.rollback()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self._is_open:
            self.rollback()
        return False


class TransactionRemoteConnection(RemoteConnection):
    """A RemoteConnection that attaches transactionId to all requests submitted
    through the traversal API (g.tx().begin() -> gtx.addV()...).

    This bridges the traversal machinery (which calls RemoteConnection.submit)
    to the Transaction (which injects the transactionId).
    """

    def __init__(self, transaction):
        super().__init__(
            transaction._client._url,
            transaction._client._traversal_source)
        self._transaction = transaction

    def submit(self, gremlin_lang):
        if not self._transaction.is_open:
            raise Exception("Transaction is not open")

        gremlin_lang.add_g(self._traversal_source)

        from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
        request_options = DriverRemoteConnection.extract_request_options(gremlin_lang)
        request_options['transactionId'] = self._transaction.transaction_id

        result_set = self._transaction._client.submit(
            gremlin_lang.get_gremlin(), request_options=request_options)
        return RemoteTraversal(result_set)

    def is_closed(self):
        return not self._transaction.is_open
