"""

    AUTHOR:

        Khushal P Soonderji

    DATE:

        CREATED: Mon, 23rd Feb, 2026
        UPDATED: Mon, 23rd Feb, 2026

    OBJECTIVE:

        To manually sync attendance for a specific time period.

    REFERENCES:

        N/A

    DOWNLOADS:

        N/A

"""


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                     IMPORT                                                    ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# To make sibling directories accessible for imports:
import sys
sys.path.append(".")
sys.path.append("..")

# For system-level activities:
import os
import copy

# To work with date and time:
import time
import datetime

# To work with tabulate data:
import pandas as pd

# Cosec-related:
from cosec_web.cosec_web import CosecWeb

# TCAOFF-related:
from tcaoff.async_tcaoff import AsyncTheCAOffice

# My utils:
from utils_v2.system import files
from utils_v2.string import json
from utils_v2.string import regex
from utils_v2.date_time import date_time

# To work with datatypes:
from typing import List, Dict, Any
from collections import defaultdict

# To run a cron-like scheduler:
from apscheduler.schedulers.asyncio import AsyncIOScheduler

# For async activities:
import asyncio

# For debugging:
from icecream import IceCreamDebugger

# Common and Shared:
from scripts import common


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                             MACROS / ONE-TIME INIT                                            ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# Debugging:
printer = IceCreamDebugger(prefix = "Manual Att | ", includeContext = True)
err_printer = IceCreamDebugger(prefix = "[ERR] Manual Att | ", includeContext = True)


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                   VARIABLES                                                   ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# --- Nothing Yet


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                    CLASSES                                                    ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# --- Nothing Yet


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                   FUNCTIONS                                                   ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


async def manual_attendance(
        cosec_creds: dict,
        tcaoff_client: AsyncTheCAOffice,
        from_date: date_time.datetime = None,
        to_date: date_time.datetime = None,
        test_mode: bool = False,
) -> None:

    printer("MANUAL ATTENDANCE")

    # Try the whole process once:
    try:

        # Log in to TCAOFF:
        success = await tcaoff_client.login()
        if not success: raise RuntimeError("TCAOFF Login Failed!")

        # Try the part that needs COSEC:
        try:

            # Figure out the dates:
            now = date_time.get_current_ist_date_time()
            if not from_date: from_date = now - datetime.timedelta(days = 1)
            if not to_date: to_date = now

            # Set the correct sequence for the dates:
            if from_date > to_date: from_date, to_date = to_date, from_date

            # Get the previous day's In/Out Summary and then wait
            # for the driver's resources to get freed:
            success = common.get_in_out_summary(
                cosec_creds = cosec_creds,
                from_dt = from_date,
                to_dt = to_date,
                cache_file = common.get_manual_in_out_summary_cache_file_path,
                test_mode = test_mode
            )

            # Sync data between Cosec and TCAOFF:
            if success:
                printer("IN/OUT SUMMARY: Sync'ing with TCAOFF")
                print("SYNC FROM:", common.get_manual_in_out_summary_cache_file_path())
                await common.sync_attendance_to_tcaoff(
                    tcaoff_client = tcaoff_client,
                    cosec_in_out_summary = json.from_file(common.get_manual_in_out_summary_cache_file_path()),
                    chunk_size = 10
                )

        # If something goes wrong in the COSEC step:
        except Exception as exception:
            err_printer(exception)
            if test_mode: raise

        # Log out of TCAOFF:
        success = await tcaoff_client.logout()
        if not success: raise RuntimeError("TCAOFF Logout Failed!")

    # If something goes wrong:
    except Exception as exception:
        err_printer(exception)
        await tcaoff_client.logout()
        if test_mode: raise


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                  MAIN PROGRAM                                                 ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


if __name__ == "__main__":

    # Parse args:
    import argparse
    ap = argparse.ArgumentParser()
    ap.add_argument(
        "--test", "--test-mode",
        action = "store_true",
        default = False
    )
    ap.add_argument(
        "--verbose",
        action = "store_true",
        default = False
    )
    ap.add_argument(
        "--from-date",
        help = "The date from which you want to sync attendance.",
        default = date_time.get_current_ist_date_time()
    )
    ap.add_argument(
        "--to-date",
        help = "The date till when you want to sync attendance.",
        default = date_time.get_current_ist_date_time()
    )
    ap.add_argument(
        "--cosec-creds",
        help = "The credentials JSON from which you would like to connect to COSEC.",
        default = "cosec.json"
    )
    ap.add_argument(
        "--tcaoff-creds",
        help = "The credentials JSON from which you would like to connect to TheCAOffice.",
        default = "tcaoff.json"
    )
    ap.add_argument(
        "--org", "--organization",
        help = "When handling multiple organizations, this word will be used to keep their files separate.",
        default = "default"
    )
    args = ap.parse_args()

    # Hold temporary environment variables:
    os.environ["ORG"] = args.org

    # Read required credentials:
    cosec_creds_path = os.path.join(common.CREDS_DIR, args.cosec_creds)
    tcaoff_creds_path = os.path.join(common.CREDS_DIR, args.tcaoff_creds)
    # ---
    cosec_creds = json.from_file(cosec_creds_path)
    tcaoff_creds = json.from_file(tcaoff_creds_path)

    # Explicitly mention the expected file paths for other devs to maintain:
    print("PROJ. DIR.  :", common.PROJ_DIR)
    print("COSEC CREDS :", cosec_creds_path)
    print("TCAOFF CREDS:", tcaoff_creds_path)

    # Ensure that certain required paths exist:
    common.init_paths()

    # Date-handling:
    args.from_date = date_time.parse_date_time(args.from_date, timezone = date_time.TIMEZONE_IST)
    args.to_date = date_time.parse_date_time(args.to_date, timezone = date_time.TIMEZONE_IST)
    if args.from_date > args.to_date: args.from_date, args.to_date = args.to_date, args.from_date
    args.from_date = args.from_date.replace(hour = 0, minute = 0, second = 0, microsecond = 0)
    args.to_date = args.to_date.replace(hour = 23, minute = 59, second = 59, microsecond = 999999)
    print("From Date:", args.from_date)
    print("  To Date:", args.to_date)

    # Create the clients:
    tcaoff_client = AsyncTheCAOffice(
        username = tcaoff_creds["creds"]["username"],
        password = tcaoff_creds["creds"]["password"],
        debug = True,
        debug_only_errors = False if args.verbose else True,
    )

    # Schedule the activities:
    asyncio.run(
        manual_attendance(
            cosec_creds = cosec_creds,
            tcaoff_client = tcaoff_client,
            from_date = args.from_date,
            to_date = args.to_date,
            test_mode = args.test,
        )
    )
