# Copyright 2018 Capital One Services, LLC
#
# Licensed 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.
from __future__ import absolute_import, division, print_function, unicode_literals

import datetime
import functools
import io
import jmespath
import json
import logging
import os
import re
import shutil
import tempfile
import unittest

import pytest
import mock
import six
import yaml

from c7n import policy
from c7n.loader import PolicyLoader
from c7n.ctx import ExecutionContext
from c7n.utils import reset_session_cache
from c7n.config import Bag, Config


C7N_VALIDATE = bool(os.environ.get("C7N_VALIDATE", ""))
skip_if_not_validating = unittest.skipIf(
    not C7N_VALIDATE, reason="We are not validating schemas.")
functional = pytest.mark.functional


class CustodianTestCore(object):

    custodian_schema = None
    # thread local? tests are single threaded, multiprocess execution
    policy_loader = PolicyLoader(Config.empty())
    policy_loader.default_policy_validate = C7N_VALIDATE

    def addCleanup(self, func, *args, **kw):
        raise NotImplementedError("subclass required")

    def write_policy_file(self, policy, format="yaml"):
        """ Write a policy file to disk in the specified format.

        Input a dictionary and a format. Valid formats are `yaml` and `json`
        Returns the file path.
        """
        fh = tempfile.NamedTemporaryFile(mode="w+b", suffix="." + format, delete=False)
        if format == "json":
            fh.write(json.dumps(policy).encode("utf8"))
        else:
            fh.write(yaml.dump(policy, encoding="utf8", Dumper=yaml.SafeDumper))

        fh.flush()
        self.addCleanup(os.unlink, fh.name)
        self.addCleanup(fh.close)
        return fh.name

    def get_temp_dir(self):
        """ Return a temporary directory that will get cleaned up. """
        temp_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, temp_dir)
        return temp_dir

    def get_context(self, config=None, session_factory=None, policy=None):
        if config is None:
            self.context_output_dir = self.get_temp_dir()
            config = Config.empty(output_dir=self.context_output_dir)
        ctx = ExecutionContext(