from msal import ConfidentialClientApplication
import requests
import csv
from typing import List, Dict, Any, Union

# Define your Azure AD and API configurations
TENANT_ID = '82360567-02b6-4a45451f-a4z6-910a811b8131'
CLIENT_ID = 'a3d88cc7-8889-42356548-bd3b-f5689372f07084'
CLIENT_SECRET = 'ibh8Q~LVSzZeeewdeWF546456UHNSoUBP.lz8GBmenXGJTlnbdU'
SCOPE = ['api://a3d88cc7-0789-4238-bd3hb-456456f89667372f07084/.default']

# Define API endpoint configurations
data_endpoint_config = {
    'projects': {
        'fields': 'projects?select=id,name,route,imeis,subline,ws10Icon,routeSecondLayer',
        'order': '&order=name.asc&limit=10',
    },
    'latestDeviceData': {
        'fields': 'devices',
        'order': '&order=name.desc',
    },
    'data': {
        'fields': 'data?select=id,version,imei,timestamp,network,data,project,location,latest',
        'order': '&order=timestamp.desc&limit=25',
    },
}

# Function to retrieve access token using MSAL
def get_access_token(tenant_id: str, client_id: str, client_secret: str, scope: List[str]) -> Union[str, None]:
    authority = f"https://login.microsoftonline.com/{tenant_id}"
    app = ConfidentialClientApplication(
        client_id,
        authority=authority,
        client_credential=client_secret,
    )
    result = app.acquire_token_for_client(scopes=scope)
    if 'access_token' in result:
        return result['access_token']
    else:
        print('Failed to retrieve access token:', result.get('error_description', 'Unknown error'))
        return None

# Function to call API with access token
def call_api_data(access_token: str, query: str) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json',
    }
    url = f"https://api.vodafone.dev/iot-db/{query}"

    print(f"Requesting URL: {url}")  # Debug: Print URL
    print(f"Request Headers: {headers}")  # Debug: Print headers

    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()  # Raise an error for bad status codes

        return response.json()
    except requests.exceptions.HTTPError as http_err:
        print(f"HTTP error occurred: {http_err}")
        print("Response content:", response.text)  # Print full response content
    except Exception as err:
        print(f"Other error occurred: {err}")

    return {}  # Return empty dictionary if request fails

# Function to get device data
def get_device_data(query_name: str) -> Union[List[Dict[str, Any]], Dict[str, Any]]:
    try:
        access_token = get_access_token(TENANT_ID, CLIENT_ID, CLIENT_SECRET, SCOPE)
        if access_token:
            query_config = data_endpoint_config.get(query_name, {})
            query_fields = query_config.get('fields', '')
            query_order = query_config.get('order', '')
            query = f"{query_fields}{query_order}"  # Combine fields and order
            if query:
                return call_api_data(access_token, query)
            else:
                print(f'No query found for query name: {query_name}')
        else:
            print('Failed to retrieve access token.')
    except Exception as e:
        print(f'Error retrieving data: {str(e)}')

    return []

# Function to convert data to CSV
def write_data_to_csv(data: List[Dict[str, Any]], filename: str):
    if not data:
        print("No data to write to CSV.")
        return

    # Extract header from the first data item keys
    headers = data[0].keys()

    try:
        with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
            writer = csv.DictWriter(csvfile, fieldnames=headers)
            writer.writeheader()
            writer.writerows(data)
        print(f"Data successfully written to {filename}")
    except Exception as e:
        print(f"Error writing to CSV: {e}")

# Fetch latest device data and write to CSV
if __name__ == '__main__':
    query_name = 'data'  # Example query name (replace with actual query name)
    device_data = get_device_data(query_name)
    
    # Check if device_data is in the expected format
    if isinstance(device_data, dict):
        # If data is returned as a dictionary, try to get the list of items
        device_data = device_data.get('items', [])

    # Convert to CSV
    write_data_to_csv(device_data, 'device_data.csv')
