#!/usr/bin/env python

# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
#
# 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 annotations

import re
import subprocess
import sys
from pathlib import Path

if __name__ not in ("__main__", "__mp_main__"):
    raise SystemExit(
        "This file is intended to be executed as an executable program. You cannot use "
        f"it as a module.To run this script, run the ./{__file__} command"
    )

SCRIPT_DIR = Path(__file__).resolve().parent
# We just check if the first line of the license is in the file. This is
# enough to check that the file is okay.
LICENSE_TEXT = (
    (SCRIPT_DIR / "assets" / "license-template.txt").read_text().splitlines()[0]
)

IGNORE_PATTERN = re.compile(
    # Exclude CI files.
    r"^\.(github)/"
    # Exclude images.
    r"|\.(?:png|jpg|jpeg|gif|ttf|woff|otf|eot|woff2|ico|svg)$"
    # Exclude playwright test assets folder.
    r"|e2e_playwright/test_assets/.*$"
    # Exclude js file we use for testing st.html.
    r"|^lib/tests/streamlit/elements/test_html\.js"
    # Exclude css file we use for testing st.html.
    r"|^lib/tests/streamlit/elements/test_html\.css"
    # Exclude files, because they make it obvious which product they relate to.
    r"|(LICENSE|NOTICES|CODE_OF_CONDUCT\.md|README\.md|CONTRIBUTING\.md|SECURITY.md)$"
    # Exclude files, because they do not support comments
    r"|\.(json|prettierrc|nvmrc|mdc|md)$"
    # Exclude generated files, because they don't have any degree of creativity.
    r"|yarn\.lock$"
    # Exclude pytest config files, because they don't have any degree of creativity.
    r"|pytest\.ini$"
    r"|\.coveragerc$"
    # Exclude empty files, because they don't have any degree of creativity.
    r"|py\.typed$"
    # Exclude dev-tools configuration files, because they don't have any
    # degree of creativity.
    r"|^(\.dockerignore|\.editorconfig|\.gitignore|\.gitmodules)$"
    r"|^frontend/(\.dockerignore|\.eslintrc.js|\.prettierignore)$"
    r"|^frontend/\.yarn"  # Exclude everything in the .yarn folder
    r"|^component-lib/\.yarn"
    r"|^frontend/component-v2-lib/\.yarn"  # Exclude everything in the .yarn folder
    r"|(\.dockerignore|MANIFEST\.in|mypy\.ini)$"
    r"|^.*-requirements\.txt$"
    r"|min-constraints-gen\.txt"
    r"|\.isort\.cfg$"
    # Exclude all .gitignore files
    r"|\.gitignore$"
    # Excluding test files, because adding headers may cause tests to fail.
    r"|/(fixtures|__snapshots__|test_data|data|test)/"
    # Exclude vendored files.
    r"|/vendor/|^vendor/|^component-lib/declarations/apache-arrow"
    r"|proto/streamlit/proto/openmetrics_data_model\.proto"
    # Exclude patch files.
    r"|\.patch$",
    re.IGNORECASE,
)


def main() -> None:
    git_files = sorted(
        subprocess.check_output(["git", "ls-files", "--no-empty-directory"])
        .decode()
        .strip()
        .splitlines()
    )

    invalid_files_count = 0
    for fileloc in git_files:
        if IGNORE_PATTERN.search(fileloc):
            continue
        filepath = Path(fileloc)
        # Exclude submodules
        if not filepath.is_file():
            continue

        try:
            file_content = filepath.read_text(encoding="utf-8")
            if LICENSE_TEXT not in file_content:
                print("Found file without license header", fileloc)
                invalid_files_count += 1
        except Exception:
            print(
                f"Failed to open the file: {fileloc}. Is it binary file?",
            )
            invalid_files_count += 1

    print("Invalid files count:", invalid_files_count)
    if invalid_files_count > 0:
        sys.exit(1)


main()
