#!/usr/bin/python3
# SPDX-License-Identifier: LicenseRef-Proprietary
"""Opt exact historical installer defaults into Coswall without changing personal settings."""

import os
from pathlib import Path
import stat
import sys
import tempfile
import tomllib


SHARE = Path('/usr/share/gravitas')
PREVIOUS = ('compositor-preview1.toml', 'compositor-preview3.toml', 'compositor-preview3-launcher.toml',
            'compositor-preview4.toml', 'compositor-preview8.toml')


def migrate(path, share=SHARE):
    """Migrate a pristine regular config once, preserving its first backup and file mode."""
    if path.is_symlink() or not path.exists():
        return False
    with os.fdopen(os.open(path, os.O_RDONLY | os.O_NOFOLLOW), 'rb') as stream:
        metadata = os.fstat(stream.fileno())
        if not stat.S_ISREG(metadata.st_mode) or metadata.st_uid != os.geteuid():
            raise ValueError('The compositor config must be a regular file owned by the login user.')
        original = stream.read()
    if not any(original == (share / 'defaults' / name).read_bytes() for name in PREVIOUS):
        return False
    # A previous backup also makes an intentional return to the old default stick.
    backup = path.with_name(path.name + '.pre-coswall')
    if backup.exists() or backup.is_symlink():
        return False
    changed = (share / 'compositor.toml').read_bytes()
    if tomllib.loads(changed.decode('utf-8')).get('background', {}).get('effect') != 'coswall':
        raise ValueError('The packaged default does not enable Coswall; leave the existing config unchanged.')

    def unchanged():
        latest = path.lstat()
        if (latest.st_dev, latest.st_ino, latest.st_mtime_ns, latest.st_ctime_ns, latest.st_size) != (
                metadata.st_dev, metadata.st_ino, metadata.st_mtime_ns, metadata.st_ctime_ns, metadata.st_size) or path.read_bytes() != original:
            raise RuntimeError('Settings changed during background migration; try again at the next login.')

    with tempfile.NamedTemporaryFile(mode='wb', dir=path.parent, delete=False) as stream:
        temporary = Path(stream.name)
        try:
            stream.write(changed)
            stream.flush()
            os.fsync(stream.fileno())
            os.fchmod(stream.fileno(), stat.S_IMODE(metadata.st_mode))
            unchanged()
            try:
                descriptor = os.open(backup, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
            except FileExistsError:
                return False
            with os.fdopen(descriptor, 'wb') as saved:
                os.fchmod(saved.fileno(), stat.S_IMODE(metadata.st_mode))
                saved.write(original)
                saved.flush()
                os.fsync(saved.fileno())
            unchanged()
            os.replace(temporary, path)
        finally:
            temporary.unlink(missing_ok=True)
    return True


def main():
    path = Path(os.environ.get('XDG_CONFIG_HOME', Path.home() / '.config')) / 'gravitas/compositor.toml'
    try:
        if migrate(path):
            print('Gravitas: enabled Coswall for the stock desktop; original config saved with .pre-coswall.')
    except (OSError, ValueError, RuntimeError) as error:
        # A default migration must not prevent a session from using its existing settings.
        print(f'Gravitas background migration: {error}', file=sys.stderr)


if __name__ == '__main__':
    main()
