# ws_package/controllers/user_controller_silent.py
# MDM / standalone silent agent — stealth_login via user_token_file.txt (no Electron DB).

import asyncio
from typing import Optional
import configparser
from ws_package.services.user_service import UserService
from ws_package.entities.user_entity import UserEntity
from ws_package.entities.org_entity import OrgEntity
from ws_package.utils.token import get_user_token
from ws_package.configs import config
from ws_package.configs.security import Security_config
from ws_package.log.writer import LogWriter
from tzlocal import get_localzone
import platform, sys
from pathlib import Path
from asyncio.exceptions import TimeoutError
from ws_package.models.base import async_session, UserDetail
from sqlalchemy import select, desc
import os
import hmac
import hashlib
from ws_package.utils.db_lock_manager import db_lock_manager

logger = LogWriter.file(__name__)


class SilentUserController:
    def __init__(self):
        # Instance-specific state (converted from class-level)
        self.user_service = UserService()
        self.config = configparser.ConfigParser()
        self.config.read('config.ini')
        # Removed individual db_write_lock - now using centralized db_lock_manager

    async def get_last_user(self) -> UserEntity | None:
        logger.info(f'Fetching last user in case of server down case')
        # Use centralized read lock for database read operations
        with db_lock_manager.read_lock():
            async with async_session() as session:
                query = select(UserDetail).order_by(desc(UserDetail.id)).limit(1)
                result = await session.execute(query)
                user_data = result.scalars().first()
                if user_data:
                    user_entity = UserEntity(
                        username=user_data.username,
                        name=user_data.name,
                        timezone=user_data.timezone,
                        token=user_data.token,
                        org_id=user_data.org_id,
                        user_id=user_data.user_id,
                        sd_token=user_data.sd_token,
                        bucket=user_data.bucket,
                        timezone_preference=getattr(user_data, "timezone_preference", 1),
                    )
                else:
                    user_entity = None
            return user_entity

    def get_file_path(self):
        if getattr(sys, 'frozen', False) and platform.system() == "Windows":
            appdata_token = (
                Path(os.environ.get("APPDATA", "")) / "Workstatus" / "user_token_file.txt"
            )
            if appdata_token.is_file():
                file_path = appdata_token
            else:
                script_path = Path(sys.executable).resolve()
                file_path = script_path.parent / "user_token_file.txt"
        elif getattr(sys, 'frozen', False) and platform.system() == "Linux":
            script_path = Path(sys.executable).resolve()
            target_directory = script_path.parents[0]
            file_path = target_directory / "user_token_file.txt"
        elif getattr(sys, 'frozen', False) and  sys.platform == "darwin":
            db_dir = Path.home() / "Library/Application Support/Workstatus"
            db_dir.mkdir(parents=True, exist_ok=True)
            file_path = db_dir / "user_token_file.txt"
        else:
            script_path = Path(__file__).resolve()
            target_directory = script_path.parents[5]   
            file_path = target_directory / "user_token_file.txt"
       
        if file_path.exists():
            logger.info(f"File Path : {file_path}")
            return file_path
        else:
            logger.info(f"Error: {file_path} not found.")
            return None
   
    def developer(self):
        file_path = self.get_file_path()
        if file_path:
            with open(file_path, "r", encoding="utf-8") as file:
                content = file.read()
                return content

    def generate_workstatus_hmac_signature(self, user_token: str, shared_secret: str) -> str:
        """
        Generate the X-Workstatus-HMAC-SHA256 header value.
        """
        signature = hmac.new(
            key=shared_secret.encode('utf-8'),
            msg=user_token.encode('utf-8'),
            digestmod=hashlib.sha256
        ).hexdigest()
        return signature

    def get_os_type(self):
            if platform.system() == "Darwin":
                return "Mac"
            return platform.system()

    async def authenticate(self) -> UserEntity | None:
        logger.info("Starting stealth_login authentication from user_token_file.txt")
        user_token = self.developer()
        if user_token is None:
            logger.info(f"User token is None")
            os._exit(1)
        self.user_service.application_login_url = config("application_login_url")
        self.user_service.headers = {"apptype": "py","X-Workstatus-HMAC-SHA256": self.generate_workstatus_hmac_signature(user_token, Security_config("shared_secret", "Security")), "deviceType": self.get_os_type()}
        user = self.user_service.authenticate_user({"user_token": user_token, "device_type": self.get_os_type(), "app_version": "7.0"})
        logger.info(f"deviceType: {self.get_os_type()}")
        if user is None:
            logger.info(f"Login api response is None fetching old user")
            return await self.get_last_user()
        response_data, bucket = user

        response_data['username'] = response_data.get('email')
        response_data['user_id'] = response_data.get('id')

        user_entity = UserEntity(
            **response_data,
            sd_token=response_data.get('token'),
            bucket=bucket
        )
        saved = await self.__save_user(user_entity)
        return saved or user_entity
    
    
    async def get_user_org(self, user_entity: UserEntity) -> OrgEntity | None:
        self.user_service.application_org_config_url = config('application_org_config_url')
        sd_token = user_entity.sd_token
        org_id = user_entity.org_id
        user_id = user_entity.user_id
        self.user_service.headers = {
            'SDToken': str(sd_token),
            'OrgID': str(org_id),
            'UserID': str(user_id),
            'Authorization': f'Bearer {sd_token}',
        }
        payload = {"user_id": user_id, "org_id": org_id}

        try:
            # Add a timeout of 10 seconds to fetch_user_org
            response_data = self.user_service.fetch_user_org(payload)
        except Exception as e:
            logger.info(f"Error in fetch_user_org: {e}")
            return None

        if response_data is None:
            return None

        # Extract weekly_limit data if present
        weekly_limit_data = response_data.get("weekly_limit")
        if weekly_limit_data:
            # Add weekly_limit fields to response_data for OrgEntity
            response_data["weekly_limit"] = weekly_limit_data
            response_data["org_week_start_day"] = weekly_limit_data.get("org_week_start_day")
            response_data["worked_total_hours_week"] = weekly_limit_data.get("worked_total_hours_week")
            response_data["worked_total_hours_week_leaving_today"] = weekly_limit_data.get("worked_total_hours_week_leaving_today")
            response_data["daily_limit"] = weekly_limit_data.get("daily_limit")
            response_data["weekly_limit_hours"] = weekly_limit_data.get("weekly_limit")
            response_data["worked_total_hours_today"] = weekly_limit_data.get("worked_total_hours_today")
            # Extract limit_action from weekly_limit object
            response_data["limit_action"] = weekly_limit_data.get("limit_action")
        
        # Extract idle_time_limit_in_seconds from API response
        if "idle_time_limit_in_seconds" in response_data:
            response_data["idle_time_limit_in_seconds"] = response_data.get("idle_time_limit_in_seconds", 3600)
        else:
            response_data["idle_time_limit_in_seconds"] = 3600  # Default fallback

        from ws_package.entities.org_entity import normalize_timezone_preference

        response_data["timezone_preference"] = normalize_timezone_preference(
            response_data.get("timezone_preference", 1)
        )

        org_entity = OrgEntity(**response_data)

        # If user_timezone is different from system timezone on Linux
        # if platform.system() == "Linux":
        #     local_timezone = get_localzone()
        #     if str(local_timezone) != str(org_entity.user_timezone):
        #         exit()

        try:
            # Add a timeout of 10 seconds to get_user_org
            user_org = await asyncio.wait_for(
                self.user_service.get_user_org(user_id=user_entity.user_id), timeout=10
            )
        except TimeoutError:
            logger.info("Timeout: get_user_org took too long.")
            user_org = None

        if user_org is None:
            return await self.__save_user_org(org_entity)
        return org_entity

    async def __save_user(self, user_entity: UserEntity):
        return await self.user_service.save_user(user_entity)
    
    async def __save_user_org(self, org_entity: OrgEntity):
        return await self.user_service.save_user_org(org_entity)


class UserLogin:
    def __init__(self, user: SilentUserController):
        self.user = user
        self.user_entity: Optional[UserEntity] = None

    def __enter__(self):
        self.user_entity = asyncio.run(self.user.authenticate())
        return self.user_entity

    def __exit__(self, type, value, traceback):
        self.user = None
        self.user_entity = None


# Backward-compatible alias
UserController = SilentUserController