#!/usr/bin/env python3
"""
Daneshyar — Apache2 Configuration Script
Run ON the server as root after PHP/Apache are installed.

Usage:
  sudo python3 scripts/configure_apache.py
  sudo python3 scripts/configure_apache.py --app-dir /var/www/daneshyar --server-name 91.107.131.171

What it does:
  - Writes a production VirtualHost config with security headers
  - Enables required Apache modules
  - Disables default site, enables daneshyar site
  - Sets up custom ErrorDocument paths (404 served by Laravel)
  - Hardens directory/file access
  - Reloads Apache
"""

from __future__ import annotations

import argparse
import os
import subprocess
import sys
from pathlib import Path


# ─── CONFIG ──────────────────────────────────────────────────────────────────
DEFAULT_APP_DIR     = "/var/www/html"
DEFAULT_SERVER_NAME = "91.107.131.171"
APACHE_CONF_PATH    = "/etc/apache2/sites-available/daneshyar.conf"
# ─────────────────────────────────────────────────────────────────────────────


def run(cmd: str, *, check: bool = True) -> int:
    print(f"  -> {cmd}")
    result = subprocess.run(cmd, shell=True, check=False)
    if check and result.returncode != 0:
        print(f"  [FAILED] exit code {result.returncode}")
        sys.exit(result.returncode)
    return result.returncode


def require_root() -> None:
    if os.name != "nt" and os.getuid() != 0:
        print("ERROR: This script must run as root.")
        print("       sudo python3 scripts/configure_apache.py")
        sys.exit(1)


def write_vhost(app_dir: str, server_name: str) -> None:
    config = fr"""\
# Daneshyar — Apache2 VirtualHost
# Generated by scripts/configure_apache.py

<VirtualHost *:80>
    ServerName {server_name}
    DocumentRoot {app_dir}/public

    # ── Directory config ──────────────────────────────────────────
    <Directory {app_dir}/public>
        AllowOverride All
        Require all granted
        Options -Indexes -MultiViews
        DirectoryIndex index.php index.html
    </Directory>

    # ── Block access to sensitive paths ──────────────────────────
    <DirectoryMatch "^{app_dir}/(\.git|\.env|storage/logs|bootstrap/cache|config|database|routes|app|vendor/bin)">
        Require all denied
    </DirectoryMatch>

    <FilesMatch "(\.env|composer\.(json|lock)|package\.json|artisan|webpack\.mix\.js|vite\.config\.(js|ts))$">
        Require all denied
    </FilesMatch>

    # ── Security headers ─────────────────────────────────────────
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "camera=(self), microphone=(self), display-capture=(self), geolocation=()"

    # ── Compression ──────────────────────────────────────────────
    <IfModule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
        AddOutputFilterByType DEFLATE text/javascript application/javascript application/json
        AddOutputFilterByType DEFLATE image/svg+xml application/x-font-ttf application/x-font-woff
    </IfModule>

    # ── Static asset caching ─────────────────────────────────────
    <IfModule mod_expires.c>
        ExpiresActive On
        ExpiresByType image/jpg  "access plus 1 year"
        ExpiresByType image/jpeg "access plus 1 year"
        ExpiresByType image/png  "access plus 1 year"
        ExpiresByType image/gif  "access plus 1 year"
        ExpiresByType image/svg+xml "access plus 1 year"
        ExpiresByType image/webp "access plus 1 year"
        ExpiresByType text/css   "access plus 6 months"
        ExpiresByType application/javascript "access plus 6 months"
        ExpiresByType application/x-font-woff2 "access plus 1 year"
        ExpiresByType text/html  "access plus 0 seconds"
    </IfModule>

    # ── Logs ─────────────────────────────────────────────────────
    ErrorLog  ${{APACHE_LOG_DIR}}/daneshyar_error.log
    CustomLog ${{APACHE_LOG_DIR}}/daneshyar_access.log combined
</VirtualHost>
"""
    Path(APACHE_CONF_PATH).write_text(config, encoding="utf-8")
    print(f"  Wrote: {APACHE_CONF_PATH}")


def main() -> None:
    parser = argparse.ArgumentParser(description="Configure Apache2 for Daneshyar.")
    parser.add_argument("--app-dir",     default=DEFAULT_APP_DIR,     help=f"Path to app on server (default: {DEFAULT_APP_DIR})")
    parser.add_argument("--server-name", default=DEFAULT_SERVER_NAME, help=f"Apache ServerName (default: {DEFAULT_SERVER_NAME})")
    args = parser.parse_args()

    require_root()

    print(f"\n=== Apache2 Configuration ==="  )
    print(f"  App dir:     {args.app_dir}")
    print(f"  Server name: {args.server_name}")

    print("\n[1/5] Enabling required Apache modules...")
    run("a2enmod rewrite")
    run("a2enmod headers")
    run("a2enmod expires")
    run("a2enmod deflate")
    run("a2enmod ssl")

    print("\n[2/5] Writing VirtualHost config...")
    write_vhost(args.app_dir, args.server_name)

    print("\n[3/5] Disabling default site, enabling daneshyar...")
    run("a2dissite 000-default.conf", check=False)
    run("a2dissite default-ssl.conf", check=False)
    run("a2ensite daneshyar.conf")

    print("\n[4/5] Testing Apache config...")
    code = run("apache2ctl configtest", check=False)
    if code != 0:
        print("\n[WARNING] Apache config test failed. Check the config above.")
        print("          You may need to fix .htaccess or directory paths.")
    else:
        print("  Config test passed.")

    print("\n[5/5] Reloading Apache2...")
    run("systemctl reload apache2")

    sep = "-" * 50
    print(f"\n{sep}")
    print("  [OK] Apache2 configured")
    print(sep)
    print(f"\n  DocumentRoot : {args.app_dir}/public")
    print(f"  Config file  : {APACHE_CONF_PATH}")
    print(f"  Error log    : /var/log/apache2/daneshyar_error.log")
    print(f"\n  Test in browser: http://{args.server_name}/")
    print(f"\n  If you see 403 Forbidden:")
    print(f"    Check: ls -la {args.app_dir}/public/")
    print(f"    Perms: chown -R www-data:www-data {args.app_dir}")
    print(sep)


if __name__ == "__main__":
    main()
