import os
import subprocess
import tempfile
from datetime import date
from pathlib import Path

from wpiformat.config import Config
from wpiformat.licenseupdate import LicenseUpdate

from .test_tasktest import *


class OpenTemporaryDirectory:
    def __init__(self):
        self.prev_dir = os.getcwd()

    def __enter__(self):
        self.temp_dir = tempfile.TemporaryDirectory()
        os.chdir(self.temp_dir.name)
        return self.temp_dir

    def __exit__(self, type, value, traceback):
        os.chdir(self.prev_dir)


def test_licenseupdate():
    year = str(date.today().year)

    file_appendix = """#pragma once

#include <iostream>

int main() {
  std::cout << "Hello World!";
}"""

    # pragma once at top of file
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        file_appendix,
        f"""/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */

"""
        + file_appendix,
        True,
    )

    # pragma once at top of file preceded by newline
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        "\n" + file_appendix,
        f"""/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */

"""
        + file_appendix,
        True,
    )

    # File containing up-to-date license preceded by newline
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        f"""

/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */

"""
        + file_appendix,
        f"""/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */

"""
        + file_appendix,
        True,
    )

    # File containing up-to-date range license
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        f"""/*                                Company Name                                */
// Copyright (c) 2011-{year} Company Name. All Rights Reserved.

"""
        + file_appendix,
        f"""/*                                Company Name                                */
/* Copyright (c) 2011-{year} Company Name. All Rights Reserved.                 */

"""
        + file_appendix,
        True,
    )

    # File containing up-to-date license with one year
    contents = (
        f"""/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */

"""
        + file_appendix
    )
    run_and_check_file(LicenseUpdate(), "./Test.h", contents, contents, True)

    # File with three newlines between license and include guard
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        f"""/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */


"""
        + file_appendix,
        f"""/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */

"""
        + file_appendix,
        True,
    )

    # File with only one newline between license and include guard
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        f"""/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */
"""
        + file_appendix,
        f"""/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */

"""
        + file_appendix,
        True,
    )

    # File with multiline comment spanning multiple lines of license header
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        """/*
 * Autogenerated file! Do not manually edit this file. This version is regenerated
 * any time the publish task is run, or when this file is deleted.
 */

const char* WPILibVersion = "";""",
        f"""/*                                Company Name                                */
/* Copyright (c) {year} Company Name. All Rights Reserved.                      */

/*
 * Autogenerated file! Do not manually edit this file. This version is regenerated
 * any time the publish task is run, or when this file is deleted.
 */

const char* WPILibVersion = "";""",
        True,
    )

    # File containing license year range in different postion than template
    # (If the year isn't extracted, the range will be replaced with one year and
    # the test will fail.)
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        f"""/*                                Company Name                                */
/* Copyright (c) Company Name 2011-{year}. All Rights Reserved.                 */

"""
        + file_appendix,
        f"""/*                                Company Name                                */
/* Copyright (c) 2011-{year} Company Name. All Rights Reserved.                 */

"""
        + file_appendix,
        True,
    )

    # Ensure "/*" after "*/" on same line is detected
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        """/*----------------------------------------------------------------------------*/
/* Copyright (c) 2011 FIRST. All Rights Reserved.                             */
/* Open Source Software - may be modified and shared by FRC teams. The code   */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project.                                                               */
/*----------------------------------------------------------------------------*//*

blah

*/
""",
        f"""/*                                Company Name                                */
/* Copyright (c) 2011-{year} Company Name. All Rights Reserved.                 */

""",
        True,
    )

    # File excluded from license update isn't modified
    contents = f"""/* Copyright (c) Company Name 2011-{year}. */

"""
    run_and_check_file(LicenseUpdate(), "./Excluded.h", contents, contents, True)

    # Ensure license regex matches
    run_and_check_file(
        LicenseUpdate(),
        "./Test.h",
        """/* Company Name */
/* Copyright (c) 1992-2015 Company Name. All Rights Reserved. */

"""
        + file_appendix,
        f"""/*                                Company Name                                */
/* Copyright (c) 1992-{year} Company Name. All Rights Reserved.                 */

"""
        + file_appendix,
        True,
    )

    # Ensure excluded files won't be processed
    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    assert not LicenseUpdate().should_process_file(config_file, "./Excluded.h")

    # Create git repo to test license years for commits
    with OpenTemporaryDirectory():
        subprocess.run(["git", "init", "-q"])

        # Add base files
        with open(".styleguide-license", "w") as file:
            file.write("// Copyright (c) {year}")
        with open(".styleguide", "w") as file:
            file.write("cppSrcFileInclude {\n" + r"\.cpp$")
        subprocess.run(["git", "add", ".styleguide-license"])
        subprocess.run(["git", "add", ".styleguide"])
        subprocess.run(["git", "commit", "-q", "-m", '"Initial commit"'])

        # Add file with commit date of last year and range through this year
        with open("last-year.cpp", "w") as file:
            file.write(f"// Copyright (c) 2017-{year}")
        subprocess.run(["git", "add", "last-year.cpp"])
        subprocess.run(["git", "commit", "-q", "-m", '"Last year"'])
        last_iso_year = f"{int(year) - 1}-01-01T00:00:00"
        subprocess.Popen(
            ["git", "commit", "-q", "--amend", "--no-edit", f"--date={last_iso_year}"],
            env={**os.environ, "GIT_COMMITTER_DATE": last_iso_year},
        ).wait()

        # Add file with commit date of this year and range through this year
        with open("this-year.cpp", "w") as file:
            file.write(f"// Copyright (c) 2017-{year}")
        subprocess.run(["git", "add", "this-year.cpp"])
        subprocess.run(["git", "commit", "-q", "-m", '"This year"'])

        # Add file with commit date of next year and range through this year
        with open("next-year.cpp", "w") as file:
            file.write(f"// Copyright (c) 2017-{year}")
        subprocess.run(["git", "add", "next-year.cpp"])
        subprocess.run(["git", "commit", "-q", "-m", '"Next year"'])
        next_iso_year = f"{int(year) + 1}-01-01T00:00:00"
        subprocess.Popen(
            ["git", "commit", "-q", "--amend", "--no-edit", f"--date={next_iso_year}"],
            env={**os.environ, "GIT_COMMITTER_DATE": next_iso_year},
        ).wait()

        # Create uncommitted file with no year
        Path("no-year.cpp").touch()

        # Run wpiformat on last-year.cpp
        with open("last-year.cpp", "r") as input:
            lines = input.read()
        output, success = LicenseUpdate().run_pipeline(
            config_file, "last-year.cpp", lines
        )
        assert output == f"// Copyright (c) 2017-{int(year) - 1}\n\n"

        # Run wpiformat on last-year.cpp with uncommitted changes. It should
        # update to next year instead of keeping previous year
        with open("last-year.cpp", "a") as input:
            input.write("change\n")
        output, success = LicenseUpdate().run_pipeline(
            config_file, "last-year.cpp", lines + "change\n"
        )
        assert (
            output
            == f"""// Copyright (c) 2017-{year}

change
"""
        )

        # Erase changes made to last-year.cpp in previous test
        with open("last-year.cpp", "w") as input:
            input.write(lines)

        # Run wpiformat on this-year.cpp
        with open("last-year.cpp", "r") as input:
            lines = input.read()
        output, success = LicenseUpdate().run_pipeline(
            config_file, "this-year.cpp", lines
        )
        assert (
            output
            == f"""// Copyright (c) 2017-{year}

"""
        )

        # Run wpiformat on next-year.cpp
        with open("next-year.cpp", "r") as input:
            lines = input.read()
        output, success = LicenseUpdate().run_pipeline(
            config_file, "next-year.cpp", lines
        )
        assert (
            output
            == f"""// Copyright (c) 2017-{int(year) + 1}

"""
        )

        # Run wpiformat on no-year.cpp
        # Should have current calendar year
        with open("no-year.cpp", "r") as input:
            lines = input.read()
        output, success = LicenseUpdate().run_pipeline(
            config_file, "no-year.cpp", lines
        )
        assert (
            output
            == f"""// Copyright (c) {year}

"""
        )
