# 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 warnings
from typing import Set, Union

import libcst as cst
from libcst import BaseExpression, FlattenSentinel, RemovalSentinel
from libcst.metadata import PositionProvider, QualifiedName, QualifiedNameProvider

from airphin.core.rules.config import Config
from airphin.core.transformer.imports import ImportTransformer
from airphin.core.transformer.operators import OpTransformer


class Transformer(cst.CSTTransformer):
    """CST Transformer route class from airflow to dolphinscheduler-sdk-python.

    The main class to call each rules to migrate, just like a router, currently will route to `imports` and
    `operators` transformer.
    """

    METADATA_DEPENDENCIES = (
        QualifiedNameProvider,
        PositionProvider,
    )

    def __init__(self, config: Config):
        super().__init__()
        self.config: Config = config

    @staticmethod
    def _get_qualified_name(qualifie: Set[QualifiedName]) -> str:
        if len(qualifie) > 1:
            warnings.warn(
                "QualifiedNameProvider get more than one qualified name, will use the first one.",
                RuntimeWarning,
            )
        for q in qualifie:
            return q.name

    # @m.call_if_inside(
    #     m.Call(
    #         func=m.MatchMetadataIfTrue(
    #             meta.QualifiedNameProvider,
    #             lambda qualnames: any(
    #                 n.name in call_cov for n in qualnames
    #             ),
    #         )
    #     )
    # )
    def leave_Call(
        self, original_node: cst.Call, updated_node: cst.Call
    ) -> BaseExpression:
        qnp = self.get_metadata(QualifiedNameProvider, original_node)
        if qnp:
            qnp_name = self._get_qualified_name(qnp)
            if qnp_name in self.config.calls:
                return updated_node.visit(OpTransformer(self.config, qnp_name))
        return updated_node

    def leave_ImportFrom(
        self, original_node: cst.ImportFrom, updated_node: cst.ImportFrom
    ) -> Union[
        cst.BaseSmallStatement, FlattenSentinel[cst.BaseSmallStatement], RemovalSentinel
    ]:
        """Migrate from import statement."""
        return updated_node.visit(ImportTransformer(self.config))
