#!/usr/bin/env python3
"""Root-deploy Passenger WSGI entrypoint for Amana Literature Ministry NG.

Designed for cPanel shared hosting where BOTH:
  https://amanaliterature.ng
  https://m.amanaliterature.ng
use /home/churchin/amanaliterature.ng as the same document root.

This app is request-driven. It serves static files with explicit MIME types and
delegates /api routes to api.app.application. It does not start a daemon, bind a
private port, or require Flask/FastAPI/gunicorn/uvicorn/PHP.
"""
from pathlib import Path
import mimetypes
import os
import sys
from urllib.parse import urlsplit

sys.dont_write_bytecode = True
APP_ROOT = Path(__file__).resolve().parent
if str(APP_ROOT) not in sys.path:
    sys.path.insert(0, str(APP_ROOT))
if str(APP_ROOT / 'api') not in sys.path:
    sys.path.insert(0, str(APP_ROOT / 'api'))

# cPanel/Python 3.11 MIME tables can be sparse on shared hosts. Be explicit so
# browsers render CSS/JS instead of downloading or blocking them under nosniff.
mimetypes.add_type('text/html', '.html')
mimetypes.add_type('text/css', '.css')
mimetypes.add_type('application/javascript', '.js')
mimetypes.add_type('application/json', '.json')
mimetypes.add_type('image/svg+xml', '.svg')
mimetypes.add_type('image/png', '.png')
mimetypes.add_type('image/jpeg', '.jpg')
mimetypes.add_type('image/jpeg', '.jpeg')
mimetypes.add_type('image/gif', '.gif')
mimetypes.add_type('image/webp', '.webp')
mimetypes.add_type('image/x-icon', '.ico')
mimetypes.add_type('font/woff', '.woff')
mimetypes.add_type('font/woff2', '.woff2')
mimetypes.add_type('font/ttf', '.ttf')
mimetypes.add_type('font/otf', '.otf')

from api.app import application as api_application  # noqa: E402

PUBLIC_HOSTS = {'amanaliterature.ng', 'www.amanaliterature.ng'}
MOBILE_HOSTS = {'m.amanaliterature.ng'}
STATIC_ROOTS = ('public_web', 'member_web', 'admin_web', 'static', 'config')
ROOT_PUBLIC_ASSETS = {'app.js', 'styles.css', 'favicon.ico', 'favicon.svg', 'manifest.json'}
ROOT_MEMBER_ASSETS = {'app.js', 'styles.css', 'app_config.js', 'favicon.ico', 'favicon.svg', 'manifest.json'}
ASSET_DIRS = ('assets', 'fonts', 'images', 'img', 'icons', 'media')
TEXT_TYPES = {'application/javascript', 'application/json', 'image/svg+xml'}


def _host(environ):
    raw = str(environ.get('HTTP_HOST') or environ.get('SERVER_NAME') or '').split(':', 1)[0].lower()
    return raw.strip('.')


def _request_path(environ):
    raw = environ.get('PATH_INFO')
    if raw in (None, ''):
        raw = environ.get('REQUEST_URI') or environ.get('RAW_URI') or '/'
    path = urlsplit(str(raw)).path or '/'
    if not path.startswith('/'):
        path = '/' + path
    return path


def _inside(child, parent):
    try:
        return os.path.commonpath([str(child.resolve()), str(parent.resolve())]) == str(parent.resolve())
    except ValueError:
        return False


def _candidate_from(relative_path):
    candidate = (APP_ROOT / str(relative_path).lstrip('/')).resolve()
    for root_name in STATIC_ROOTS:
        allowed_root = APP_ROOT / root_name
        if _inside(candidate, allowed_root) and candidate.is_file():
            return candidate
    return None


def _first_existing(paths):
    for path in paths:
        candidate = _candidate_from(path)
        if candidate:
            return candidate
    return None


def _static_aliases(path_info, host):
    path = urlsplit(str(path_info or '/')).path or '/'
    mobile_host = host in MOBILE_HOSTS
    aliases = []

    if path in {'/', '', '/index.html', '/index.htm'}:
        aliases.append('member_web/index.html' if mobile_host else 'public_web/index.html')
        return aliases

    if path in {'/admin', '/admin/', '/admin/index.html', '/admin/index.htm'}:
        aliases.append('admin_web/index.html')
        return aliases
    if path.startswith('/admin/'):
        aliases.append('admin_web/' + path[len('/admin/'):])
        return aliases

    if path in {'/member', '/member/', '/member/index.html', '/member/index.htm', '/mobile', '/mobile/'}:
        aliases.append('member_web/index.html')
        return aliases
    if path.startswith('/member/'):
        aliases.append('member_web/' + path[len('/member/'):])
        return aliases
    if path.startswith('/mobile/'):
        aliases.append('member_web/' + path[len('/mobile/'):])
        return aliases

    for root_name in STATIC_ROOTS:
        prefix = '/' + root_name + '/'
        if path == '/' + root_name:
            aliases.append(root_name + '/index.html')
            return aliases
        if path.startswith(prefix):
            aliases.append(path.lstrip('/'))
            return aliases

    leaf = path.lstrip('/')
    if '/' not in leaf:
        if mobile_host and leaf in ROOT_MEMBER_ASSETS:
            aliases.append('member_web/' + leaf)
        elif leaf in ROOT_PUBLIC_ASSETS:
            aliases.append('public_web/' + leaf)
        aliases.append('static/' + leaf)
        return aliases

    first = leaf.split('/', 1)[0]
    if first in ASSET_DIRS:
        if mobile_host:
            aliases.extend(['member_web/' + leaf, 'public_web/' + leaf, 'static/' + leaf])
        else:
            aliases.extend(['public_web/' + leaf, 'member_web/' + leaf, 'static/' + leaf])
        return aliases

    aliases.append(leaf)
    return aliases


def _static_candidate(path_info, host):
    return _first_existing(_static_aliases(path_info, host))


def _headers_for(path, body_length):
    content_type = mimetypes.guess_type(str(path))[0] or 'application/octet-stream'
    if content_type.startswith('text/') or content_type in TEXT_TYPES:
        content_type += '; charset=utf-8'
    return [
        ('Content-Type', content_type),
        ('Content-Length', str(body_length)),
        ('X-Content-Type-Options', 'nosniff'),
        ('Cache-Control', 'no-cache' if path.name in {'index.html', 'app_config.js'} else 'public, max-age=300'),
    ]


def _serve_static(path, environ, start_response):
    body = path.read_bytes()
    start_response('200 OK', _headers_for(path, len(body)))
    if environ.get('REQUEST_METHOD', 'GET').upper() == 'HEAD':
        return [b'']
    return [body]


def _not_found(start_response):
    body = b'Amana Literature Ministry NG resource not found.'
    start_response('404 Not Found', [('Content-Type', 'text/plain; charset=utf-8'), ('Content-Length', str(len(body))), ('X-Content-Type-Options', 'nosniff')])
    return [body]


def application(environ, start_response):
    environ.setdefault('CIL_APP_ROOT', str(APP_ROOT))
    environ.setdefault('CIL_WORKSPACE_ROOT', str(APP_ROOT.parent))
    path_info = _request_path(environ)

    if path_info == '/api':
        environ['PATH_INFO'] = '/api/health'
        return api_application(environ, start_response)
    if path_info.startswith('/api/'):
        return api_application(environ, start_response)

    candidate = _static_candidate(path_info, _host(environ))
    if candidate:
        return _serve_static(candidate, environ, start_response)
    return _not_found(start_response)
