import os
import pytz
from typing import Literal
from fastapi import Request, Query, Depends, Header, APIRouter, HTTPException
from fastapi.responses import JSONResponse
from datetime import datetime, timedelta
from connectors.firebase.firebase import Firebase
from api.feature.ad_integration.facebook.FacebookAds import FacebookAdIntegration

from models.ad_integration import *

from dotenv import load_dotenv
load_dotenv()

import logging
logging.basicConfig(level=logging.INFO)
timezone_utc = pytz.utc
timezone_bkk = pytz.timezone('Asia/Bangkok')

fb = Firebase(host=os.environ.get("FIREBASE_HOST"))

router = APIRouter()

LOGGING_PREFIX = "api_offline_schema"

@router.get("/{channel}", response_model=DataResponse, description="Get ad connect account details")
async def get_ad_connect(
    default_request: Request,
    channel: Literal['all','facebook', 'google_customer_match'],
    property_id: str,
):
    try:
        if channel != 'all':
            ad_account_context = fb.db.reference().child(f"account/{property_id}/ad_connect/account/{channel}").get()
            if ad_account_context:
                return JSONResponse(status_code=200, content={'status': 'ok', 'data': ad_account_context, 'message': 'Success'})

            return JSONResponse(status_code=200, content={'status': 'Not found', 'message': f'This property is not yet configured with a {channel} Ad account', 'data': []})
        else:
            ad_account_context = fb.db.reference().child(f"account/{property_id}/ad_connect/account").get()
            if ad_account_context:
                return JSONResponse(status_code=200, content={'status': 'ok', 'data': ad_account_context, 'message': 'Success'})
            return JSONResponse(status_code=200, content={'status': 'Not found', 'message': 'This property is not yet configured with a Facebook Ad account', 'data': []})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.post("/account", description="Add a new ad connect account")
async def add_ad_connect(default_request: Request, request: ManageAdAccountRequest):
    now = datetime.now(timezone_utc)
    time = now.strftime('%Y-%m-%d %H:%M:%S')
    try:
        for acc in request.data:
            if acc.channel == 'facebook':
                if not str(acc.ad_account_id).startswith("act_"):
                    acc.ad_account_id = 'act_' + str(acc.ad_account_id)

                #Step: check permision
                fbAds = FacebookAdIntegration(
                    access_token=os.environ.get("FB_TOKEN"),
                    app_id=os.environ.get("FB_APP_ID"),
                    app_secret=os.environ.get("FB_APP_SECRET"),
                    ad_account_id=acc.ad_account_id
                )
                is_grant, message = fbAds.check_permission()
                if not is_grant:
                    return JSONResponse(status_code=400, content={'status': 'Bad Request', 'message': message})

                fb.db.reference().child(f"account/{request.property_id}/ad_connect/account/facebook/{acc.ad_account_id}/id").set(acc.ad_account_id)
                fb.db.reference().child(f"account/{request.property_id}/ad_connect/account/facebook/{acc.ad_account_id}/name").set(acc.name)
                fb.db.reference().child(f"account/{request.property_id}/ad_connect/account/facebook/{acc.ad_account_id}/createdate").set(time)
                fb.db.reference().child(f"account/{request.property_id}/ad_connect/account/facebook/{acc.ad_account_id}/lastupdate").set(time)
        
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': 'Success', 'message': 'Ad account connection was created successfully'})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.get("/account/{channel}/{ad_account_id}", response_model=DataResponse, description="Get ad connect account details")
async def get_ad_connect(
    default_request: Request,
    channel: Literal['all','facebook', 'google_customer_match'],
    ad_account_id: str,
    property_id: str  = Query(..., description="Property ID"),
):
    try:
        if channel == 'all':
            ad_account_context = fb.db.reference().child(f"account/{property_id}/ad_connect/account").get()
            if ad_account_context:
                return JSONResponse(status_code=200, content={'status': 'ok', 'data': ad_account_context, 'message': 'Success'})
            return JSONResponse(status_code=200, content={'status': 'Not found', 'message': 'This property is not yet configured with a Ad account', 'data': []})

        if ad_account_id != 'all':
            ad_account_context = fb.db.reference().child(f"account/{property_id}/ad_connect/account/{channel}/{ad_account_id}").get()
            if ad_account_context:
                return JSONResponse(status_code=200, content={'status': 'ok', 'data': ad_account_context, 'message': 'Success'})

            return JSONResponse(status_code=404, content={'status': 'Not found', 'message': 'This ad account is not found'})
        else:
            ad_account_context = fb.db.reference().child(f"account/{property_id}/ad_connect/account/{channel}").get()
            if ad_account_context:
                return JSONResponse(status_code=200, content={'status': 'ok', 'data': ad_account_context, 'message': 'Success'})
            return JSONResponse(status_code=200, content={'status': 'Not found', 'message': f'This property is not yet configured with a {channel} Ad account', 'data': []})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.delete("/account/{channel}/{ad_account_id}", description="Delete ad connect account")
async def delete_ad_connect(
    default_request: Request,
    channel: Literal['facebook', 'google_customer_match'],
    ad_account_id: str,
    property_id: str = Query(..., description="Property ID"),
):
    try:
        #check
        ad_account_context = fb.db.reference().child(f"account/{property_id}/ad_connect/account/{channel}/{ad_account_id}").get(shallow=True)
        if not ad_account_context:
            return JSONResponse(status_code=404, content={'status': 'not found', 'message': 'This ad account is not found'})
        
        fb.db.reference().child(f"account/{property_id}/ad_connect/account/{channel}/{ad_account_id}").delete()
        return JSONResponse(status_code=200, content={'status': 'ok', 'message': f"Ad account {ad_account_id} connection was deleted"})
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.post("/audience-link", description="Link audiences to ad connect account")
async def link_ad_audience(default_request: Request, request: ManageAdAccountAudienceRequest):
    now = datetime.now(timezone_utc)
    time = now.strftime('%Y-%m-%d %H:%M:%S')
    try:
        #check ad_account_id
        ad_account_ids = request.ad_account_ids
        for acc in ad_account_ids:
            ad_account_id_exsit = fb.db.reference().child(f"account/{request.property_id}/ad_connect/account/{acc.channel}/{acc.ad_account_id}").get(shallow=True)
            if not ad_account_id_exsit:
                return JSONResponse(status_code=404, content={'status': 'not found', 'message': f'Ad account {acc.ad_account_id} not found in {acc.channel}'})
    
        #Get audience context
        audiences_context = {}
        for au in request.audiences:
            ref_audience = fb.db.reference().child(f"account/{request.property_id}/audience/{au.audience_id}")
            if not ref_audience.get(shallow=True):
                continue


            au_name = ref_audience.child(f"name").get()
            description = ref_audience.child(f"description").get() or ""
            context = {
                "audience_id": au.audience_id,
                "audience_name": str(au_name).lower().replace(' ','_'),
                "audience_description": description,
                "method": au.methods
            }
            audiences_context[au.audience_id] = context


        #Loop over audience_combination
        create_log = []
        for au in audiences_context:
            for method in au['method']:
                custom_audience_name = f"C360" + "_" + au['audience_name'] + "_" + method
                for acc in ad_account_ids:
                    if acc.channel == 'facebook':
                        fbAds = FacebookAdIntegration(
                            access_token=os.environ.get("FB_TOKEN"),
                            app_id=os.environ.get("FB_APP_ID"),
                            app_secret=os.environ.get("FB_APP_SECRET"),
                            ad_account_id=acc.ad_account_id
                        )

                        if method == 'APPEND':
                            status = fbAds.create_audience(name=custom_audience_name, description=audiences_context[au]['audience_description'])
                            context = {
                                    'ad_account_id': acc.ad_account_id,
                                    'audience_id': au,
                                    "platform_audience_context":  status or {},
                                    "status": 'success' if status else 'fail',
                                    'message': 'Create connect to ad account success' if status else 'Create connect to ad account fail',
                                    "createdate": time if status else None,
                                    "lastupdate": time if status else None
                                }
                            create_log.append(context)
                            logging.info(f"Ad account {acc.ad_account_id} audience {au} creation status: {context['status']}")
                            if status:
                                context_audience_data = {
                                    "ad_account_id": {acc.ad_account_id},
                                    "platform_audience_id": status,
                                    "createdate": time if status else None,
                                    "lastupdate": time if status else None
                                }
                                fb.db.reference().child(f"account/{request.property_id}/ad_connect/job/{au['audience_id']}/platforms/facebook/{status}").set(context_audience_data)
                        elif method == 'DELETE':
                            context = {
                                'ad_account_id': acc.ad_account_id,
                                'audience_id': au,
                                'message': 'Method not supported',
                                'status': 'method_fail'
                            }
                            create_log.append(context)
                    else:
                        context = {
                            'ad_account_id': acc.ad_account_id,
                            'audience_id': au,
                            'message': 'Method not supported',
                            'status': 'channel_fail'
                        }
                        create_log.append(context)

        return {'status': 'ok', 'message': f'Add new audiences link successfully','data': create_log}, 200
    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})

@router.get("/audience-link", description="Get linked audiences for ad connect account", response_model=DataResponse)
async def get_linked_audiences(
    default_request: Request,
    property_id: str = Query(..., description="Property ID"),
    channel: Literal['all','facebook', 'google_customer_match'] = Query('all', description="Ad channel"),
    ad_account_id: str = Query('all', description="Ad account ID")
):
    try:
        #check all
        ref_path = fb.db.reference(f"account/{property_id}/ad_connect/job")
        if not ref_path.get(shallow=True):
            return JSONResponse(status_code=404, content={'status': 'not_found', 'data': [], 'message': 'No audiences found'})
        
        if channel == 'all':
            audiences = ref_path.get()
            return {'status': 'ok', 'data': audiences, 'message': 'Get all audiences success'}, 200

        elif channel != 'all' and ad_account_id == 'all':
            audiences = ref_path.child(channel).get()
            return {'status': 'ok', 'data': audiences, 'message': 'Get audiences by channel success'}, 200

        else:
            audiences = ref_path.child(channel).child(ad_account_id).get()
            return {'status': 'ok', 'data': audiences, 'message': 'Get audiences by ad account success'}, 200

    except Exception as e:
        logging.error(f"Error parsing {LOGGING_PREFIX}_{default_request.path_params}: {e}")
        return JSONResponse(status_code=500, content={'status': 'error', 'message': str(e)})