import yaml
import redis
import logging
import argparse
from rq import Queue
from pathlib import Path
from archivingsystem.api import Endpoint
from archivingsystem.worker import Worker
from archivingsystem.common import Handler
from archivingsystem.common import listing
from archivingsystem.scheduler import Scheduler
from archivingsystem.validation import validating
from archivingsystem.retimestamping import Checker
from archivingsystem.database import Database, Base

log = logging.getLogger()
# Leave level configuration on Handler
log.setLevel(logging.NOTSET)

def load_configuration(path: Path):
    """
    Loads configuration from YAML file.
    """
    with open(path) as f:
        return yaml.load(f, Loader=yaml.SafeLoader)

def main():
    """
    The main function of the Archiving system. It is set as the `archivingsystem` 
    entry point (in `setup.py`), or it can be executed directly by running `core.py`.
    """
    parser = argparse.ArgumentParser(prog='archivingsystem')

    parser.add_argument(
        "-V",
        "--version",
        help="show server version",
        action="version",
        version="%(prog)s 0.1.0"
    )

    parser.add_argument(
        "-c",
        "--config", 
        metavar="/path/to/config.yml",
        default="config/config.yml",
        help="load configuration from file, default %(default)s",
        type=Path
    )

    parser.add_argument(
        "-va",
        "--validate-all",
        help="validate integrity of all packages",
        action="store_true"
    )

    parser.add_argument(
        "-v",
        "--validate",
        metavar="FileID",
        help="validate archived package integrity",
        type=int
    )

    parser.add_argument(
        "-la",
        "--list-all",
        help="list of all archived files",
        action="store_true"
    )

    parser.add_argument(
        "-l",
        "--list",
        metavar="FileID",
        help="list details of file specified by `FileID`",
        type=int
    )

    # Get argument values from parser
    args = parser.parse_args()

    # Load configuratin object from file
    config = load_configuration(args.config)

    # Modify root logger with custom Handler
    log.addHandler(Handler(config["log_level"]))

    # Create database connection
    db = Database(config)

    # Generate database schema (if doesn't exist)
    # TODO: Implement Alembic to add database schema migration capabilities
    Base.metadata.create_all(db.engine)

    # Create Redis connection and queues
    r = redis.Redis(host=config["redis"]["host"], port=config["redis"]["port"])
    qa = Queue("toArchive", connection=r, default_timeout=3600) # Increase job timeouts to 1h
    qr = Queue("toRetimestamp", connection=r, default_timeout=3600) # Increase job timeouts to 1h

    if args.list:
        # List single file
        listing.single(db, args.list)
    elif args.list_all:
        # List all files
        listing.all(db)
    elif args.validate:
        # Validate single file
        validating.single(config, args.validate)
    elif args.validate_all:
        # Validate all files
        validating.all(db, config)
    else:
        # Start API endpoint
        Endpoint(config, qa).run()

        # Start archivation worker
        Worker("archivation", config, qa, r).run()

        # Start retimestamping worker
        Worker("retimestamping", config, qr, r).run()

        # Start Scheduler to periodically run Checker on archived files
        Scheduler("retimestamping", config["archiving"]["timestamping"]["retimestamping"]["interval"], Checker(config, qr).run).run()

    log.debug('End of main')

if __name__ == "__main__":
    main()