"""
PaySpace Deel Local Payroll API SDK (v2.0)

A comprehensive Python SDK for interacting with the Deel Local Payroll API v2.0.
Supports all endpoints with proper v2.0 compliance including lookup endpoints.

Environments:
- Production: https://api.payspace.com/odata/v2.0
- Staging: https://apistaging.payspace.com/odata/v2.0
- Development: https://localhost:44393/odata/v2.0

Note: API v2.0 breaking changes:
- Lookup endpoints now prefixed with /Lookup/
- Date format must be yyyy-MM-dd for Edm.Date types
- Rate limits: 2000 requests/min (prod), 200 requests/min (staging)
"""

import requests
from typing import Optional, Dict, List, Any, Union
from datetime import datetime, date
from urllib.parse import quote
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class PaySpaceEnvironment:
    """Environment configurations for PaySpace API v2.0"""
    PRODUCTION = "https://api.payspace.com/odata/v2.0"
    STAGING = "https://apistaging.payspace.com/odata/v2.0"
    DEVELOPMENT = "https://localhost:44393/odata/v2.0"


class PaySpaceClient:
    """Main client for PaySpace API interactions"""

    def __init__(self, 
                 client_id: Optional[str] = None,
                 client_secret: Optional[str] = None,
                 access_token: Optional[str] = None,
                 environment: str = PaySpaceEnvironment.PRODUCTION,
                 auth_url: Optional[str] = None):
        """
        Initialize PaySpace API client
        
        Args:
            client_id: OAuth client ID (for authentication)
            client_secret: OAuth client secret (for authentication)
            access_token: Pre-existing OAuth 2.0 access token (optional if using client_id/secret)
            environment: API environment URL
            auth_url: Authentication URL (defaults based on environment)
        """
        self.base_url = environment
        self.client_id = client_id
        self.client_secret = client_secret
        self._token = access_token
        self._companies: List[Dict] = []
        
        # Set default auth URL based on environment (v2.0 spec)
        if auth_url:
            self.auth_url = auth_url
        elif environment == PaySpaceEnvironment.PRODUCTION:
            self.auth_url = "https://identity.yourhcm.com/connect/token"
        elif environment == PaySpaceEnvironment.STAGING:
            self.auth_url = "https://staging-identity.yourhcm.com/connect/token"
        elif environment == PaySpaceEnvironment.DEVELOPMENT:
            self.auth_url = "https://localhost:44392/connect/token"
        else:
            self.auth_url = "https://identity.yourhcm.com/connect/token"
        
        self.session = requests.Session()
        self._update_session_headers()

    def _update_session_headers(self):
        """Update session headers with current token and required v2.0 headers"""
        token = self._token if self._token else ""
        self.session.headers.update({
            'Authorization': f'Bearer {token}',
            'Accept': 'application/json;odata.metadata=minimal',
            'OData-MaxVersion': '4.0',
            'User-Agent': 'payspace.com python-sdk/2.0'
        })

    def authenticate(self) -> str:
        """
        Grab that access token and the list of companies. Fail loudly if it bombs.
        
        Returns:
            Access token string
        """
        if self._token:
            return self._token  # Reuse if still valid, but hey, no expiry check—add if you care
        
        if not self.client_id or not self.client_secret:
            raise ValueError("client_id and client_secret are required for authentication")
        
        data = {
            'api-scope': 'api.read_only',
            'client_id': self.client_id,
            'client_secret': self.client_secret
        }
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
        
        logger.info(f"Authenticating with {self.auth_url}")
        response = requests.post(self.auth_url, data=data, headers=headers)
        response.raise_for_status()
        resp_json = response.json()
        
        self._token = resp_json['access_token']
        
        # Extract companies from group structure
        group_companies = resp_json.get('group_companies', [])
        _companies = []
        if group_companies:
            for group in group_companies:
                for company in group.get('companies', []):
                    _companies.append(company)
        self._companies = _companies
        
        if not self._companies:
            logger.warning("Warning: No companies found in auth response. Check your setup.")
        else:
            logger.info(f"Authenticated successfully. Found {len(self._companies)} companies.")
        
        # Update session with new token
        self._update_session_headers()
        
        return self._token

    def get_available_companies(self) -> List[Dict]:
        """
        Get list of companies available to the authenticated user
        
        Returns:
            List of company dictionaries from authentication response
        """
        if not self._companies:
            self.authenticate()
        return self._companies

    @property
    def access_token(self) -> str:
        """Get current access token, authenticating if necessary"""
        if not self._token:
            self.authenticate()
        return self._token

    def _make_request(self, endpoint: str, params: Optional[Dict] = None) -> Dict[str, Any]:
        """
        Make HTTP GET request to API
        
        Args:
            endpoint: API endpoint path
            params: Query parameters
            
        Returns:
            JSON response data
        """
        # Ensure we have a valid token
        if not self._token:
            self.authenticate()
        
        url = f"{self.base_url}/{endpoint}"
        logger.info(f"Requesting: {url}")
        
        try:
            response = self.session.get(url, params=params)
            response.raise_for_status()
            data = response.json()
            
            # Handle OData pagination
            results = data.get('value', [])
            while '@odata.nextLink' in data:
                next_url = data['@odata.nextLink']
                response = self.session.get(next_url)
                response.raise_for_status()
                data = response.json()
                results.extend(data.get('value', []))
            
            return {'value': results} if results else data
        except requests.exceptions.RequestException as e:
            logger.error(f"API request failed: {e}")
            raise

    # =============================
    # COMPANY ENDPOINTS
    # =============================

    def get_companies(self, company_search: Optional[str] = None, group_search: Optional[str] = None) -> List[Dict]:
        """
        Get all companies (Companies.dax)
        
        Endpoint: /Company
        
        Args:
            company_search: Filter by company name or trading name
            group_search: Filter by company group
            
        Returns:
            List of company records
        """
        endpoint = "Company"
        params = {}
        
        # Build filter
        filters = []
        if company_search:
            search_encoded = quote(company_search.replace("'", "''"))
            filters.append(f"(contains(CompanyName, '{search_encoded}') or contains(TradingName, '{search_encoded}'))")
        if group_search:
            search_encoded = quote(group_search.replace("'", "''"))
            filters.append(f"contains(CompanyGroup, '{search_encoded}')")
        
        if filters:
            params['$filter'] = ' or '.join(filters)
        
        return self._make_request(endpoint, params).get('value', [])

    def get_company_names(self, company_search: Optional[str] = None) -> List[Dict]:
        """
        Get company names list (Companies.dax - CompanyNames variant)
        
        Endpoint: /Company
        
        Args:
            company_search: Filter by company name
            
        Returns:
            List of company IDs and names
        """
        endpoint = "Company"
        params = {'$select': 'CompanyId,CompanyName'}
        
        if company_search:
            search_encoded = quote(company_search.replace("'", "''"))
            params['$filter'] = f"contains(CompanyName, '{search_encoded}')"
        
        return self._make_request(endpoint, params).get('value', [])

    def get_company_frequency(self, company_id: int) -> List[Dict]:
        """
        Get company pay frequencies (CompanyFrequency.dax)
        
        Endpoint: /{companyId}/CompanyFrequency
        Sequence: Sequence_CompanyFrequency_With_Keys
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of pay frequencies for the company
        """
        endpoint = f"{company_id}/CompanyFrequency"
        return self._make_request(endpoint).get('value', [])

    def get_company_runs(self, company_id: int, frequency: str, 
                        start_date: Optional[date] = None, 
                        end_date: Optional[date] = None) -> List[Dict]:
        """
        Get payroll runs (Runs.dax)
        
        Endpoint: /{companyId}/CompanyRun
        Sequence: Sequence_CompanyRun, Sequence_CompanyRunWithDateRange
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency (e.g., "Monthly", "Weekly")
            start_date: Filter runs from this date
            end_date: Filter runs to this date
            
        Returns:
            List of payroll run records
        """
        endpoint = f"{company_id}/CompanyRun"
        params = {'frequency': frequency}
        
        if start_date and end_date:
            start_str = start_date.strftime('%Y-%m-%d')
            end_str = end_date.strftime('%Y-%m-%d')
            params['$filter'] = f"PeriodStartDate ge {start_str} and PeriodStartDate le {end_str}"
        
        return self._make_request(endpoint, params).get('value', [])

    def get_company_training_courses(self, company_id: int) -> List[Dict]:
        """
        Get company training courses (CompanyTrainingCourse.dax)
        
        Endpoint: /{companyId}/CompanyTrainingCourse
        Sequence: Sequence_CompanyTrainingCourse
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of training courses
        """
        endpoint = f"{company_id}/CompanyTrainingCourse"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # EMPLOYEE BASIC INFORMATION
    # =============================

    def get_biographical(self, company_id: int, effective_year: int, 
                        effective_month: int, effective_day: int,
                        frequency: Optional[str] = None) -> List[Dict]:
        """
        Get employee biographical data (Biographical.dax)
        
        Endpoint: /{companyId}/Employee/effective/{year}-{month}-{day}?frequency={frequency}
        Sequence: Sequence_Employee_CustomFields_Frequency
        
        Args:
            company_id: Company identifier
            effective_year: Effective year
            effective_month: Effective month
            effective_day: Effective day
            frequency: Optional pay frequency filter
            
        Returns:
            List of employee biographical records
        """
        endpoint = f"{company_id}/Employee/effective/{effective_year}-{effective_month:02d}-{effective_day:02d}"
        params = {}
        
        if frequency:
            params['frequency'] = frequency
        
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_addresses(self, company_id: int, effective_year: int,
                              effective_month: int, effective_day: int) -> List[Dict]:
        """
        Get employee addresses (address.dax)
        
        Endpoint: /{companyId}/Employee/effective/{year}-{month}-{day}
        Sequence: Sequence_Employee_Address
        
        Args:
            company_id: Company identifier
            effective_year: Effective year
            effective_month: Effective month
            effective_day: Effective day
            
        Returns:
            List of employee records with address data
        """
        endpoint = f"{company_id}/Employee/effective/{effective_year}-{effective_month:02d}-{effective_day:02d}"
        return self._make_request(endpoint).get('value', [])

    def get_employee_bank_details(self, company_id: int) -> List[Dict]:
        """
        Get employee banking details (BankDetails.dax)
        
        Endpoint: /{companyId}/EmployeeBankDetail
        Sequence: Sequence_EmployeeBankDetail
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of employee bank detail records
        """
        endpoint = f"{company_id}/EmployeeBankDetail"
        return self._make_request(endpoint).get('value', [])

    def get_employee_dependants(self, company_id: int) -> List[Dict]:
        """
        Get employee dependants (Dependants.dax)
        
        Endpoint: /{companyId}/EmployeeDependant
        Sequence: Sequence_EmployeeDependant_CustomFields
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of employee dependant records
        """
        endpoint = f"{company_id}/EmployeeDependant"
        return self._make_request(endpoint).get('value', [])

    def get_employee_positions(self, company_id: int) -> List[Dict]:
        """
        Get employee positions (Positions.dax)
        
        Endpoint: /{companyId}/EmployeePosition/all
        Sequence: Sequence_EmployeePosition_CustomFields_All
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of employee position records
        """
        endpoint = f"{company_id}/EmployeePosition/all"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # PAYROLL PROCESSING
    # =============================

    def get_pay_rate_details(self, company_id: int) -> List[Dict]:
        """
        Get employee pay rate details (PayRateDetails.dax)
        
        Endpoint: /{companyId}/EmployeePayRate/all
        Sequence: Sequence_PayRateDetails_CustomFields_All
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of pay rate records
        """
        endpoint = f"{company_id}/EmployeePayRate/all"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # PAYROLL RESULTS
    # =============================

    def get_payslips(self, company_id: int, year: int, month: int, 
                    frequency: Optional[str] = None) -> List[Dict]:
        """
        Get employee payslips (Payslips.dax)
        
        Endpoint: /{companyId}/EmployeePayslip/{year}/{month}
        Sequence: Sequence_Payslips_Payslips_Filter_Frequency
        
        Args:
            company_id: Company identifier
            year: Payslip year
            month: Payslip month
            frequency: Optional frequency filter
            
        Returns:
            List of payslip records
        """
        endpoint = f"{company_id}/EmployeePayslip/{year}/{month:02d}"
        params = {}
        
        if frequency:
            params['$filter'] = f"Frequency eq '{frequency}'"
        
        return self._make_request(endpoint, params).get('value', [])

    def get_payslip_lines(self, company_id: int, year: int, month: int) -> List[Dict]:
        """
        Get payslip line items (PayslipLines.dax)
        
        Endpoint: /{companyId}/EmployeePayslipLine/{year}/{month}
        Sequence: Sequence_Payslips_PayslipLines
        
        Args:
            company_id: Company identifier
            year: Payslip year
            month: Payslip month
            
        Returns:
            List of payslip line records
        """
        endpoint = f"{company_id}/EmployeePayslipLine/{year}/{month:02d}"
        return self._make_request(endpoint).get('value', [])

    def get_payslip_leave_balances(self, company_id: int, year: int, month: int,
                                   frequency: Optional[str] = None) -> List[Dict]:
        """
        Get leave balances from payslips (PayslipLeaveBalances.dax)
        
        Endpoint: /{companyId}/EmployeePayslip/{year}/{month}
        Sequence: Sequence_Payslips_LeaveBalances_Filter_Frequency
        
        Args:
            company_id: Company identifier
            year: Payslip year
            month: Payslip month
            frequency: Optional frequency filter
            
        Returns:
            List of payslip records with leave balances
        """
        endpoint = f"{company_id}/EmployeePayslip/{year}/{month:02d}"
        params = {}
        
        if frequency:
            params['$filter'] = f"Frequency eq '{frequency}'"
        
        return self._make_request(endpoint, params).get('value', [])

    # =============================
    # LEAVE MANAGEMENT
    # =============================

    def get_leave_applications(self, company_id: int, year: int, month: int,
                              start_date: Optional[date] = None,
                              end_date: Optional[date] = None) -> List[Dict]:
        """
        Get employee leave applications (LeaveApplications.dax)
        
        Endpoint: /{companyId}/EmployeeLeaveApplication/{year}/{month}
        Sequence: Sequence_EmployeeLeaveApplications_EffectiveDate, Sequence_EmployeeLeaveApplications_DateRange
        
        Args:
            company_id: Company identifier
            year: Year
            month: Month
            start_date: Optional start date for date range filter
            end_date: Optional end date for date range filter
            
        Returns:
            List of leave application records
        """
        if start_date and end_date:
            endpoint = f"{company_id}/EmployeeLeaveApplication"
            start_str = start_date.strftime('%Y-%m-%dT00:00:00Z')
            end_str = end_date.strftime('%Y-%m-%dT00:00:00Z')
            params = {
                '$filter': f"(LeaveStartDate ge {start_str} and LeaveStartDate le {end_str}) or (LeaveEndDate ge {start_str} and LeaveEndDate le {end_str})"
            }
            return self._make_request(endpoint, params).get('value', [])
        else:
            endpoint = f"{company_id}/EmployeeLeaveApplication/{year}/{month:02d}"
            return self._make_request(endpoint).get('value', [])

    def get_leave_adjustments(self, company_id: int, year: int, month: int) -> List[Dict]:
        """
        Get leave balance adjustments (LeaeAdjustments.dax)
        
        Endpoint: /{companyId}/EmployeeLeaveAdjustment/{year}/{month}
        Sequence: Sequence_EmployeeLeaveAdjustment
        
        Args:
            company_id: Company identifier
            year: Year
            month: Month
            
        Returns:
            List of leave adjustment records
        """
        endpoint = f"{company_id}/EmployeeLeaveAdjustment/{year}/{month:02d}"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # EMPLOYEE BENEFITS & ADDITIONAL INFO
    # =============================

    def get_employee_medical(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee medical aid information (EmployeeMedical.dax)
        
        Endpoint: /{companyId}/EmployeeMedical
        Sequence: Sequence_EmployeeMedical
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of medical aid records
        """
        endpoint = f"{company_id}/EmployeeMedical"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_pension_fund(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee pension fund details (EmployeePensionFund.dax)
        
        Endpoint: /{companyId}/EmployeePensionFund
        Sequence: Sequence_EmployeePensionFund
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of pension fund records
        """
        endpoint = f"{company_id}/EmployeePensionFund"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_training(self, company_id: int) -> List[Dict]:
        """
        Get employee training records (EmployeeTraining.dax)
        
        Endpoint: /{companyId}/EmployeeTraining/all
        Sequence: Sequence_EmployeeTraining
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of training records
        """
        endpoint = f"{company_id}/EmployeeTraining/all"
        return self._make_request(endpoint).get('value', [])

    def get_employee_incidents(self, company_id: int) -> List[Dict]:
        """
        Get employee incident reports (EmployeeIncident.dax)
        
        Endpoint: /{companyId}/EmployeeIncident
        Sequence: Sequence_EmployeeIncident
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of incident records
        """
        endpoint = f"{company_id}/EmployeeIncident"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # EMPLOYEE RECURRING/BENEFITS
    # =============================

    def get_employee_bonus_provision(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee bonus provision details
        
        Endpoint: /{companyId}/EmployeeBonusProvision
        Sequence: Sequence_EmployeeBonusProvision
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of bonus provision records
        """
        endpoint = f"{company_id}/EmployeeBonusProvision"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_company_car_detail(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee company car details
        
        Endpoint: /{companyId}/EmployeeCompanyCarDetail
        Sequence: Sequence_EmployeeCompanyCarDetail
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of company car records
        """
        endpoint = f"{company_id}/EmployeeCompanyCarDetail"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_component(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee components (recurring payroll components)
        
        Endpoint: /{companyId}/EmployeeComponent
        Sequence: Sequence_EmployeeComponent
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of employee component records
        """
        endpoint = f"{company_id}/EmployeeComponent"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_component_values(self, company_id: int) -> List[Dict]:
        """
        Get employee component values
        
        Endpoint: /{companyId}/EmployeeComponentValues
        Sequence: Sequence_EmployeeComponentValues
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of component value records
        """
        endpoint = f"{company_id}/EmployeeComponentValues"
        return self._make_request(endpoint).get('value', [])

    def get_employee_disability(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee disability information
        
        Endpoint: /{companyId}/EmployeeDisability
        Sequence: Sequence_EmployeeDisability
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of disability records
        """
        endpoint = f"{company_id}/EmployeeDisability"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_garnishee(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee garnishee (wage attachment) details
        
        Endpoint: /{companyId}/EmployeeGarnishee
        Sequence: Sequence_EmployeeGarnishee
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of garnishee records
        """
        endpoint = f"{company_id}/EmployeeGarnishee"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_group_life(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee group life insurance details
        
        Endpoint: /{companyId}/EmployeeGroupLife
        Sequence: Sequence_EmployeeGroupLife
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of group life records
        """
        endpoint = f"{company_id}/EmployeeGroupLife"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_income_protection(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee income protection insurance details
        
        Endpoint: /{companyId}/EmployeeIncomeProtection
        Sequence: Sequence_EmployeeIncomeProtection
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of income protection records
        """
        endpoint = f"{company_id}/EmployeeIncomeProtection"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_loan(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee loan details
        
        Endpoint: /{companyId}/EmployeeLoan
        Sequence: Sequence_EmployeeLoan
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of loan records
        """
        endpoint = f"{company_id}/EmployeeLoan"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_retirement_annuity(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee retirement annuity details
        
        Endpoint: /{companyId}/EmployeeRetirementAnnuity
        Sequence: Sequence_EmployeeRetirementAnnuity
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of retirement annuity records
        """
        endpoint = f"{company_id}/EmployeeRetirementAnnuity"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_saving(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee savings details
        
        Endpoint: /{companyId}/EmployeeSaving
        Sequence: Sequence_EmployeeSaving
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of savings records
        """
        endpoint = f"{company_id}/EmployeeSaving"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_union(self, company_id: int, frequency: str, period: str) -> List[Dict]:
        """
        Get employee trade union membership details
        
        Endpoint: /{companyId}/EmployeeUnion
        Sequence: Sequence_EmployeeUnion
        
        Args:
            company_id: Company identifier
            frequency: Pay frequency
            period: Period identifier
            
        Returns:
            List of union membership records
        """
        endpoint = f"{company_id}/EmployeeUnion"
        params = {'frequency': frequency, 'period': period}
        return self._make_request(endpoint, params).get('value', [])

    # =============================
    # EMPLOYEE SKILLS & QUALIFICATIONS
    # =============================

    def get_employee_skills(self, company_id: int) -> List[Dict]:
        """
        Get employee skills
        
        Endpoint: /{companyId}/EmployeeSkills
        Sequence: Sequence_EmployeeSkills
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of employee skill records
        """
        endpoint = f"{company_id}/EmployeeSkills"
        return self._make_request(endpoint).get('value', [])

    def get_employee_qualifications(self, company_id: int) -> List[Dict]:
        """
        Get employee qualifications
        
        Endpoint: /{companyId}/EmployeeQualifications
        Sequence: Sequence_EmployeeQualifications
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of employee qualification records
        """
        endpoint = f"{company_id}/EmployeeQualifications"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # EMPLOYEE SUSPENSION
    # =============================

    def get_employee_suspension(self, company_id: int, start_date: date, end_date: date) -> List[Dict]:
        """
        Get employee suspension records with date range
        
        Endpoint: /{companyId}/EmployeeSuspension
        Sequence: Sequence_EmployeeSuspension_DateRange
        
        Args:
            company_id: Company identifier
            start_date: Start date for suspension filter
            end_date: End date for suspension filter
            
        Returns:
            List of suspension records
        """
        endpoint = f"{company_id}/EmployeeSuspension"
        start_str = start_date.strftime('%Y-%m-%dT00:00:00Z')
        end_str = end_date.strftime('%Y-%m-%dT00:00:00Z')
        params = {
            '$filter': f"SuspensionDate ge {start_str} and SuspensionDate le {end_str}"
        }
        return self._make_request(endpoint, params).get('value', [])

    # =============================
    # EMPLOYEE COSTING & PROJECTS
    # =============================

    def get_recurring_costing_split(self, company_id: int) -> List[Dict]:
        """
        Get recurring costing split information
        
        Endpoint: /{companyId}/RecurringCostingSplit
        Sequence: Sequence_RecurringCostingSplit
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of costing split records
        """
        endpoint = f"{company_id}/RecurringCostingSplit"
        return self._make_request(endpoint).get('value', [])

    def get_employee_project(self, company_id: int) -> List[Dict]:
        """
        Get employee project details (already aliased as get_employee_projects)
        
        Endpoint: /{companyId}/EmployeeProject
        Sequence: Sequence_EmployeeProject
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of employee project records
        """
        endpoint = f"{company_id}/EmployeeProject"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # EMPLOYEE REVIEW
    # =============================

    def get_employee_review_template(self, company_id: int) -> List[Dict]:
        """
        Get employee review templates
        
        Endpoint: /{companyId}/EmployeeReviewTemplate
        Sequence: Sequence_EmployeeReviewTemplate
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of review template records
        """
        endpoint = f"{company_id}/EmployeeReviewTemplate"
        return self._make_request(endpoint).get('value', [])

    def get_employee_review_header(self, company_id: int) -> List[Dict]:
        """
        Get employee review headers
        
        Endpoint: /{companyId}/EmployeeReviewHeader
        Sequence: Sequence_EmployeeReviewHeader
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of review header records
        """
        endpoint = f"{company_id}/EmployeeReviewHeader"
        return self._make_request(endpoint).get('value', [])

    def get_employee_review_kpa(self, company_id: int) -> List[Dict]:
        """
        Get employee review KPAs (Key Performance Areas)
        
        Endpoint: /{companyId}/EmployeeReviewKpa
        Sequence: Sequence_EmployeeReviewKpa
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of review KPA records
        """
        endpoint = f"{company_id}/EmployeeReviewKpa"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # CUSTOM FORMS
    # =============================

    def get_employee_custom_forms(self, company_id: int) -> List[Dict]:
        """
        Get employee custom forms
        
        Endpoint: /{companyId}/EmployeeCustomForms
        Sequence: Sequence_EmployeeCustomForms
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of employee custom form records
        """
        endpoint = f"{company_id}/EmployeeCustomForms"
        return self._make_request(endpoint).get('value', [])

    def get_company_custom_forms(self, company_id: int) -> List[Dict]:
        """
        Get company custom forms
        
        Endpoint: /{companyId}/CompanyCustomForms
        Sequence: Sequence_CompanyCustomForms
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of company custom form records
        """
        endpoint = f"{company_id}/CompanyCustomForms"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # COMPANY BILLING
    # =============================

    def get_financial_transactions(self, company_id: int) -> List[Dict]:
        """
        Get company financial transactions (billing)
        
        Endpoint: /{companyId}/FinancialTransactions
        Sequence: Sequence_FinancialTransactions
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of financial transaction records
        """
        endpoint = f"{company_id}/FinancialTransactions"
        return self._make_request(endpoint).get('value', [])

    def get_company_review_process(self, company_id: int) -> List[Dict]:
        """
        Get company review process configuration
        
        Endpoint: /{companyId}/CompanyReviewProcess
        Sequence: Sequence_CompanyReviewProcess
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of review process records
        """
        endpoint = f"{company_id}/CompanyReviewProcess"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # ADDITIONAL EMPLOYEE INFO
    # =============================

    def get_biographical_including_terminated(self, company_id: int, effective_year: int,
                                             effective_month: int, effective_day: int,
                                             frequency: Optional[str] = None) -> List[Dict]:
        """
        Get employee biographical data including terminated employees
        
        Endpoint: /{companyId}/Employee/all/effective/{year}-{month}-{day}
        Sequence: Sequence_Employee_Including_Terminated
        
        Args:
            company_id: Company identifier
            effective_year: Effective year
            effective_month: Effective month
            effective_day: Effective day
            frequency: Optional pay frequency filter
            
        Returns:
            List of employee biographical records including terminated
        """
        endpoint = f"{company_id}/Employee/effective/{effective_year}-{effective_month:02d}-{effective_day:02d}"
        params = {}
        
        if frequency:
            params['frequency'] = frequency
        
        return self._make_request(endpoint, params).get('value', [])

    def get_employee_attachments(self, company_id: int) -> List[Dict]:
        """
        Get employee attachments
        
        Endpoint: /{companyId}/EmployeeAttachment
        Sequence: Sequence_EmployeeAttachment_CustomFields
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of employee attachment records
        """
        endpoint = f"{company_id}/EmployeeAttachment"
        return self._make_request(endpoint).get('value', [])

    def get_tax_profile(self, company_id: int) -> List[Dict]:
        """
        Get employee tax profiles (Employment Status)
        
        Endpoint: /{companyId}/EmployeeEmploymentStatus/all
        Sequence: Sequence_EmployeeEmploymentStatus_CustomFields_All
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of tax profile/employment status records
        """
        endpoint = f"{company_id}/EmployeeEmploymentStatus/all"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # ADDITIONAL PAYROLL RESULTS
    # =============================

    def get_costed_payslip_lines(self, company_id: int, year: int, month: int) -> List[Dict]:
        """
        Get costed payslip line items (with cost center allocations)
        
        Endpoint: /{companyId}/EmployeePayslipLine/{year}/{month}/costed
        Sequence: Sequence_Payslips_CostedPayslipLines
        
        Args:
            company_id: Company identifier
            year: Payslip year
            month: Payslip month
            
        Returns:
            List of costed payslip line records
        """
        endpoint = f"{company_id}/EmployeePayslipLine/{year}/{month:02d}/costed"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # ORGANIZATIONAL STRUCTURE
    # =============================

    def get_organization_units(self, company_id: int) -> List[Dict]:
        """
        Get organizational hierarchy units (OrganizationUnit.dax)
        
        Endpoint: /{companyId}/OrganizationUnit
        Sequence: Sequence_OrganizationUnit_Address
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of organization unit records
        """
        endpoint = f"{company_id}/OrganizationUnit"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # CONFIGURATION & LOOKUP DATA
    # =============================

    def get_currency_exchange_rates(self, company_id: int) -> List[Dict]:
        """
        Get currency exchange rates (CurrencyExchangeRates.dax)
        
        Endpoint: /CompanyGroupExchangeRate/company/{companyId}
        Sequence: Sequence_CompanyGroupExchangeRate
        
        Args:
            company_id: Company identifier
            
        Returns:
            List of exchange rate records
        """
        endpoint = f"CompanyGroupExchangeRate/company/{company_id}"
        return self._make_request(endpoint).get('value', [])

    # =============================
    # LOOKUP VALUES / REFERENCE DATA
    # =============================

    def get_activity_code_lookup(self, company_id: int) -> List[Dict]:
        """Get activity code lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/ActivityCode"
        return self._make_request(endpoint).get('value', [])

    def get_account_type_lookup(self, company_id: int) -> List[Dict]:
        """Get account type lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/AccountType"
        return self._make_request(endpoint).get('value', [])

    def get_address_country_lookup(self, company_id: int) -> List[Dict]:
        """Get address country lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/AddressCountry"
        return self._make_request(endpoint).get('value', [])

    def get_address_country_province_lookup(self, company_id: int, country: str) -> List[Dict]:
        """Get address country province lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/AddressCountry/{country}"
        return self._make_request(endpoint).get('value', [])

    def get_administrator_employee_number_lookup(self, company_id: int) -> List[Dict]:
        """Get administrator employee number lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/AdministratorEmployeeNumber"
        return self._make_request(endpoint).get('value', [])

    def get_budget_group_lookup(self, company_id: int) -> List[Dict]:
        """Get budget group lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/BudgetGroup"
        return self._make_request(endpoint).get('value', [])

    def get_car_payment_type_lookup(self, company_id: int) -> List[Dict]:
        """Get car payment type lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/CarPaymentType"
        return self._make_request(endpoint).get('value', [])

    def get_citizenship_lookup(self, company_id: int) -> List[Dict]:
        """Get citizenship lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Citizenship"
        return self._make_request(endpoint).get('value', [])

    def get_classification_lookup(self, company_id: int) -> List[Dict]:
        """Get classification lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Classification"
        return self._make_request(endpoint).get('value', [])

    def get_company_component_lookup(self, company_id: int) -> List[Dict]:
        """Get company component lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/CompanyComponent"
        return self._make_request(endpoint).get('value', [])

    def get_company_disability_lookup(self, company_id: int) -> List[Dict]:
        """Get company disability lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/CompanyDisability"
        return self._make_request(endpoint).get('value', [])

    def get_company_edb_indicator_lookup(self, company_id: int) -> List[Dict]:
        """Get company EDB indicator lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/CompanyEdbIndicator"
        return self._make_request(endpoint).get('value', [])

    def get_company_group_life_lookup(self, company_id: int) -> List[Dict]:
        """Get company group life lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/CompanyGroupLife"
        return self._make_request(endpoint).get('value', [])

    def get_company_pension_fund_lookup(self, company_id: int) -> List[Dict]:
        """Get company pension fund lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/CompanyPensionFund"
        return self._make_request(endpoint).get('value', [])

    def get_company_medical_aid_lookup(self, company_id: int) -> List[Dict]:
        """Get company medical aid lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/CompanyMedicalAid"
        return self._make_request(endpoint).get('value', [])

    def get_component_company_lookup(self, company_id: int) -> List[Dict]:
        """Get component company lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/ComponentCompany"
        return self._make_request(endpoint).get('value', [])

    def get_component_code_lookup(self, company_id: int) -> List[Dict]:
        """Get component code lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/ComponentCode"
        return self._make_request(endpoint).get('value', [])

    def get_cost_centre_code_lookup(self, company_id: int) -> List[Dict]:
        """Get cost centre code lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/CostCentreCode"
        return self._make_request(endpoint).get('value', [])

    def get_country_lookup(self, company_id: int) -> List[Dict]:
        """Get country lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Country"
        return self._make_request(endpoint).get('value', [])

    def get_currency_lookup(self, company_id: int) -> List[Dict]:
        """Get currency lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Currency"
        return self._make_request(endpoint).get('value', [])

    def get_disabled_type_lookup(self, company_id: int) -> List[Dict]:
        """Get disabled type lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/DisabledType"
        return self._make_request(endpoint).get('value', [])

    def get_directly_reports_employee_number_lookup(self, company_id: int) -> List[Dict]:
        """Get directly reports employee number lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/DirectlyReportsEmployeeNumber"
        return self._make_request(endpoint).get('value', [])

    def get_directly_reports_position_override_lookup(self, company_id: int) -> List[Dict]:
        """Get directly reports position override lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/DirectlyReportsPositionOverride"
        return self._make_request(endpoint).get('value', [])

    def get_employee_number_lookup(self, company_id: int) -> List[Dict]:
        """Get employee number lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/EmployeeNumber"
        return self._make_request(endpoint).get('value', [])

    def get_employment_action_lookup(self, company_id: int) -> List[Dict]:
        """Get employment action lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/EmploymentAction"
        return self._make_request(endpoint).get('value', [])

    def get_employment_category_lookup(self, company_id: int) -> List[Dict]:
        """Get employment category lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/EmploymentCategory"
        return self._make_request(endpoint).get('value', [])

    def get_employment_sub_category_lookup(self, company_id: int) -> List[Dict]:
        """Get employment sub-category lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/EmploymentSubCategory"
        return self._make_request(endpoint).get('value', [])

    def get_general_ledger_lookup(self, company_id: int) -> List[Dict]:
        """Get general ledger lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/GeneralLedger"
        return self._make_request(endpoint).get('value', [])

    def get_gl_grouping_code_lookup(self, company_id: int) -> List[Dict]:
        """Get GL grouping code lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/GLGroupingCode"
        return self._make_request(endpoint).get('value', [])

    def get_grade_lookup(self, company_id: int) -> List[Dict]:
        """Get grade lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Grade"
        return self._make_request(endpoint).get('value', [])

    def get_identity_type_lookup(self, company_id: int) -> List[Dict]:
        """Get identity type lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/IdentityType"
        return self._make_request(endpoint).get('value', [])

    def get_input_type_lookup(self, company_id: int) -> List[Dict]:
        """Get input type lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/InputType"
        return self._make_request(endpoint).get('value', [])

    def get_job_lookup(self, company_id: int) -> List[Dict]:
        """Get job lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Job"
        return self._make_request(endpoint).get('value', [])

    def get_language_lookup(self, company_id: int) -> List[Dict]:
        """Get language lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Language"
        return self._make_request(endpoint).get('value', [])

    def get_marital_status_lookup(self, company_id: int) -> List[Dict]:
        """Get marital status lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/MaritalStatus"
        return self._make_request(endpoint).get('value', [])

    def get_manager_employee_number_lookup(self, company_id: int) -> List[Dict]:
        """Get manager employee number lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/ManagerEmployeeNumber"
        return self._make_request(endpoint).get('value', [])

    def get_nationality_lookup(self, company_id: int) -> List[Dict]:
        """Get nationality lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Nationality"
        return self._make_request(endpoint).get('value', [])

    def get_nature_of_person_lookup(self, company_id: int) -> List[Dict]:
        """Get nature of person lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/NatureOfPerson"
        return self._make_request(endpoint).get('value', [])

    def get_organization_category_lookup(self, company_id: int) -> List[Dict]:
        """Get organization category lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/OrganizationCategory"
        return self._make_request(endpoint).get('value', [])

    def get_organization_group_lookup(self, company_id: int) -> List[Dict]:
        """Get organization group lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/OrganizationGroup"
        return self._make_request(endpoint).get('value', [])

    def get_organization_level_lookup(self, company_id: int) -> List[Dict]:
        """Get organization level lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/OrganizationLevel"
        return self._make_request(endpoint).get('value', [])

    def get_organization_position_lookup(self, company_id: int) -> List[Dict]:
        """Get organization position lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/OrganizationPosition"
        return self._make_request(endpoint).get('value', [])

    def get_organization_region_lookup(self, company_id: int) -> List[Dict]:
        """Get organization region lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/OrganizationRegion"
        return self._make_request(endpoint).get('value', [])

    def get_override_ofo_code_lookup(self, company_id: int) -> List[Dict]:
        """Get override OFO code lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/OverrideOfoCode"
        return self._make_request(endpoint).get('value', [])

    def get_override_occupational_level_lookup(self, company_id: int) -> List[Dict]:
        """Get override occupational level lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/OverrideOccupationalLevel"
        return self._make_request(endpoint).get('value', [])

    def get_passport_country_lookup(self, company_id: int) -> List[Dict]:
        """Get passport country lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/PassportCountry"
        return self._make_request(endpoint).get('value', [])

    def get_pay_point_lookup(self, company_id: int) -> List[Dict]:
        """Get pay point lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/PayPoint"
        return self._make_request(endpoint).get('value', [])

    def get_project_code_lookup(self, company_id: int) -> List[Dict]:
        """Get project code lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/ProjectCode"
        return self._make_request(endpoint).get('value', [])

    def get_preferred_race_lookup(self, company_id: int) -> List[Dict]:
        """Get preferred race lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/PreferredRace"
        return self._make_request(endpoint).get('value', [])

    def get_preferred_localization_lookup(self, company_id: int) -> List[Dict]:
        """Get preferred localization lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/PreferredLocalization"
        return self._make_request(endpoint).get('value', [])

    def get_race_lookup(self, company_id: int) -> List[Dict]:
        """Get race lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Race"
        return self._make_request(endpoint).get('value', [])

    def get_reason_lookup(self, company_id: int) -> List[Dict]:
        """Get reason lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Reason"
        return self._make_request(endpoint).get('value', [])

    def get_roster_lookup(self, company_id: int) -> List[Dict]:
        """Get roster lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Roster"
        return self._make_request(endpoint).get('value', [])

    def get_sdl_exemption_lookup(self, company_id: int) -> List[Dict]:
        """Get SDL exemption lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/SdlExemption"
        return self._make_request(endpoint).get('value', [])

    def get_suspension_reason_lookup(self, company_id: int) -> List[Dict]:
        """Get suspension reason lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/SuspensionReason"
        return self._make_request(endpoint).get('value', [])

    def get_tax_status_lookup(self, company_id: int) -> List[Dict]:
        """Get tax status lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/TaxStatus"
        return self._make_request(endpoint).get('value', [])

    def get_termination_company_run_lookup(self, company_id: int, frequency: str) -> List[Dict]:
        """Get termination company run lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/TerminationCompanyRun"
        params = {'frequency': frequency}
        return self._make_request(endpoint, params).get('value', [])

    def get_termination_reason_lookup(self, company_id: int) -> List[Dict]:
        """Get termination reason lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/TerminationReason"
        return self._make_request(endpoint).get('value', [])

    def get_title_lookup(self, company_id: int) -> List[Dict]:
        """Get title lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/Title"
        return self._make_request(endpoint).get('value', [])

    def get_trade_union_lookup(self, company_id: int) -> List[Dict]:
        """Get trade union lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/TradeUnion"
        return self._make_request(endpoint).get('value', [])

    def get_uif_exemption_lookup(self, company_id: int) -> List[Dict]:
        """Get UIF exemption lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/UifExemption"
        return self._make_request(endpoint).get('value', [])

    def get_workflow_role_lookup(self, company_id: int) -> List[Dict]:
        """Get workflow role lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/WorkflowRole"
        return self._make_request(endpoint).get('value', [])

    def get_component_code_input_type_lookup(self, company_id: int) -> List[Dict]:
        """Get component code input type lookup values (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/ComponentCodeInputType"
        return self._make_request(endpoint).get('value', [])

    def get_leave_company_run_lookup(self, company_id: int, frequency: str, 
                                    start_date: date, end_date: date) -> List[Dict]:
        """Get leave company run lookup values with date range (v2.0: /Lookup/ prefix)"""
        endpoint = f"{company_id}/Lookup/LeaveCompanyRun"
        start_str = start_date.strftime('%Y-%m-%d')
        end_str = end_date.strftime('%Y-%m-%d')
        params = {
            'frequency': frequency,
            '$filter': f"PeriodStartDate ge {start_str} and PeriodStartDate le {end_str}"
        }
        return self._make_request(endpoint, params).get('value', [])


class PaySpaceAPIHelper:
    """Helper methods for common operations"""

    @staticmethod
    def get_current_period() -> tuple:
        """Get current year and month for period-based queries"""
        now = datetime.now()
        return now.year, now.month

    @staticmethod
    def get_current_date() -> tuple:
        """Get current year, month, day for date-based queries"""
        now = datetime.now()
        return now.year, now.month, now.day

    @staticmethod
    def format_date(dt: Union[date, datetime]) -> str:
        """Format date for API queries"""
        if isinstance(dt, datetime):
            dt = dt.date()
        return dt.strftime('%Y-%m-%d')


# Example usage
# if __name__ == "__main__":
#     # Example 1: Using client_id and client_secret (recommended)
#     print("=== Example 1: Authentication with client credentials ===")
#     client = PaySpaceClient(
#         client_id="your_client_id",
#         client_secret="your_client_secret",
#         environment=PaySpaceEnvironment.PRODUCTION
#     )

#     try:
#         # Authenticate and get available companies
#         client.authenticate()
#         available_companies = client.get_available_companies()
#         print(f"Available companies from auth: {len(available_companies)}")
        
#         # Get all companies via API
#         companies = client.get_companies()
#         print(f"Found {len(companies)} companies via API")

#         if companies:
#             company_id = companies[0]['CompanyId']
#             print(f"\nUsing company_id: {company_id}")
            
#             # Get biographical data for current date
#             year, month, day = PaySpaceAPIHelper.get_current_date()
#             biographical = client.get_biographical(company_id, year, month, day)
#             print(f"Found {len(biographical)} employees")

#             # Get payslips for current period
#             year, month = PaySpaceAPIHelper.get_current_period()
#             payslips = client.get_payslips(company_id, year, month)
#             print(f"Found {len(payslips)} payslips")

#     except Exception as e:
#         print(f"Error: {e}")

#     # Example 2: Using pre-existing access token
#     print("\n=== Example 2: Using pre-existing token ===")
#     client_with_token = PaySpaceClient(
#         access_token="your_existing_token_here",
#         environment=PaySpaceEnvironment.PRODUCTION
#     )
    
#     try:
#         companies = client_with_token.get_companies()
#         print(f"Found {len(companies)} companies")
#     except Exception as e:
#         print(f"Error: {e}")
