########################################################
## Created By Gourav Gupta [gouravgupta.com] in [Feb 2026] 
## for Publicis Groupe dv360 automation task process.

## Maintainers
##  - [Gourav Gupta]
########################################################

import requests
from google.oauth2 import service_account
from google.auth.transport.requests import Request

class ApiV4:
  __BASE_URL            = "https://displayvideo.googleapis.com/v4"
  __SCOPES              = ["https://www.googleapis.com/auth/display-video"]
  
  def __init__(self, service_account_json_path: str):
    self.service_account_json_path = service_account_json_path

  def __create_header(self, token: str):
    return { 
      "Authorization": f"Bearer {token}", 
      "Accept": "application/json" 
    }

  def __get_access_token(self):
    try:
      creds = service_account.Credentials.from_service_account_file(self.service_account_json_path, scopes=self.__SCOPES)
      creds.refresh(Request())
      return creds.token
    except Exception:
      pass

  def get_io_info(self, advertiser_id: int, insertion_order_id: int):
    token = self.__get_access_token()
    
    URL = f"{self.__BASE_URL}/advertisers/{advertiser_id}/insertionOrders/{insertion_order_id}"
    headers = self.__create_header(token)

    response = requests.get(URL, headers=headers)
    response.raise_for_status()
    
    data = response.json()
    
    required = {
      "name"                                                : data.get("name"),
      "campaignId"                                          : data.get("campaignId"),
      "updateTime"                                          : data.get("updateTime"),
      "displayName"                                         : data.get("displayName"),
      "entityStatus"                                        : data.get("entityStatus"),
      "advertiserId"                                        : data.get("advertiserId"),
      "insertionOrderId"                                    : data.get("insertionOrderId"),
      
      "pacing.pacingType"                                   : data.get("pacing").get("pacingType"),
      "pacing.pacingPeriod"                                 : data.get("pacing").get("pacingPeriod"),
      "pacing.dailyMaxMicros"                               : data.get("pacing").get("dailyMaxMicros"),

      "budget.budgetUnit"                                   : data.get("budget").get("budgetUnit"),
      "budget.automationType"                               : data.get("budget").get("automationType"),
      
      "budget.budgetSegments.0.description"                 : data.get("budget").get("budgetSegments")[0].get("description"),
      "budget.budgetSegments.0.budgetAmountMicros"          : data.get("budget").get("budgetSegments")[0].get("budgetAmountMicros"), # BUDGET CALC (100000000 / 1000000) = $100 
      
      "budget.budgetSegments.0.dateRange.startDate.year"    : data.get("budget").get("budgetSegments")[0].get("dateRange").get("startDate").get("year"),
      "budget.budgetSegments.0.dateRange.startDate.month"   : data.get("budget").get("budgetSegments")[0].get("dateRange").get("startDate").get("month"),
      "budget.budgetSegments.0.dateRange.startDate.day"     : data.get("budget").get("budgetSegments")[0].get("dateRange").get("startDate").get("day"),
      
      "budget.budgetSegments.0.dateRange.endDate.year"      : data.get("budget").get("budgetSegments")[0].get("dateRange").get("endDate").get("year"),
      "budget.budgetSegments.0.dateRange.endDate.month"     : data.get("budget").get("budgetSegments")[0].get("dateRange").get("endDate").get("month"),
      "budget.budgetSegments.0.dateRange.endDate.day"       : data.get("budget").get("budgetSegments")[0].get("dateRange").get("endDate").get("day")
    }
    
    return required
  
  def remove_automatic_budget_allocation(self, advertiser_id: int, insertion_order_id: int):
    '''
      `any_amount: float = 1.0`: need this in order to toggle the radio button at io details level on dv360 
      account dashboard. please provide something else it will take 1.0 as `default`
    '''
    io = self.get_io_info_from_dv360(advertiser_id, insertion_order_id)

    updateMask = "bidStrategy.fixedBid.bidAmountMicros"

    amount = int(io["budget.budgetSegments.0.budgetAmountMicros"]) / 1000000
    if amount < 1:
      raise ValueError(f"{amount} is less the 1, make sure you pass a value greater then 1 at line level")

    json_payload = {
      "bidStrategy": { 
        "fixedBid": { 
          "bidAmountMicros": str(1000000 * amount)
        }
      }
    }

    token = self.__get_access_token()
  
    URL = f"{self.__BASE_URL}/advertisers/{advertiser_id}/insertionOrders/{insertion_order_id}"
    headers = self.__create_header(token)

    params = { "updateMask": updateMask }
    response = requests.patch(URL, json=json_payload, headers=headers, params=params)
    response.raise_for_status()
    data = response.json()

    return data
  
  def update_li_budget_amount(self, advertiser_id: int, line_item_id: int, any_amount: float = 1.0):
    '''
      @NOTE: DON'T USE THIS, GOOGLE NOT ALLOWING IT FOR `YouTube & partners ads`
    
      `any_amount: float = 1.0`: need this in order to toggle the radio button at io details level on dv360 
      account dashboard. please provide something else it will take 1.0 as `default`
    '''
    updateMask = "bidStrategy.fixedBid.bidAmountMicros"

    amount = int(any_amount)
    if amount < 1:
      raise ValueError(f"{amount} is less the 1, make sure you pass a value greater then 1 at line level")

    json_payload={
      "bidStrategy": { 
        "fixedBid": { 
          "bidAmountMicros": str(1000000 * amount) 
        }
      }
    }

    token = self.__get_access_token()
    
    URL = f"{self.__BASE_URL}/advertisers/{advertiser_id}/lineItems/{line_item_id}"
    headers = self.__create_header(token)
    
    params = { "updateMask": updateMask }
    response = requests.patch(URL, json=json_payload, headers=headers, params=params)
    response.raise_for_status()
    data = response.json()
 
    return data