package kz.konturai.parser.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import kz.konturai.parser.config.TargetingApiConfig;
import kz.konturai.parser.dto.TikTokCampaignDto;
import kz.konturai.parser.exception.TikTokApiException;
import kz.konturai.parser.model.TargetingAd;
import kz.konturai.parser.model.TargetingAdSet;
import kz.konturai.parser.model.TargetingAudienceProfile;
import kz.konturai.parser.model.TargetingCampaign;
import kz.konturai.parser.enums.CampaignObjective;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;

import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//@Service
@RequiredArgsConstructor
@Slf4j
public class TikTokAdsService {

    private final TargetingApiConfig apiConfig;
    private final WebClient.Builder webClientBuilder;
    private final SocialMediaCredentialsService credentialsService;
    private final ObjectMapper objectMapper;

    private WebClient webClient;

    @PostConstruct
    public void init() {
        this.webClient = webClientBuilder.baseUrl(apiConfig.getTiktok().getBaseUrl()).build();
    }

    public List<Map<String, Object>> getAdvertisers(String accessToken) {
        return executeApiCall(accessToken, "/oauth2/advertiser/get/", Map.of(
                "app_id", apiConfig.getTiktok().getAppId(),
                "secret", apiConfig.getTiktok().getAppSecret()
        ), List.class);
    }

    public String createCampaign(String accessToken, String advertiserId, TargetingCampaign campaign) {
        Map<String, Object> body = new HashMap<>();
        body.put("advertiser_id", advertiserId);
        body.put("campaign_name", campaign.getName());
        body.put("objective_type", mapObjective(campaign.getObjective()));
        body.put("budget_mode", "BUDGET_MODE_DAY");
        body.put("budget", campaign.getBudget().getDailyBudget() / apiConfig.getKztUsdRate());

        JsonNode response = executeApiCall(accessToken, "/campaign/create/", body, JsonNode.class);
        return getResponseId(response, "campaign_id");
    }

    public String createAdGroup(String accessToken, String advertiserId, String tiktokCampaignId,
                                TargetingAdSet adSet, TargetingAudienceProfile audience) {
        Map<String, Object> body = new HashMap<>();
        body.put("advertiser_id", advertiserId);
        body.put("campaign_id", tiktokCampaignId);
        body.put("adgroup_name", adSet.getName());
        body.put("placement_type", "PLACEMENT_TYPE_NORMAL");
        body.put("placements", List.of("PLACEMENT_TIKTOK"));
        
        // Audience
        body.put("location_ids", List.of("6252001")); // Placeholder KZ/Almaty mapping
        
        body.put("optimization_goal", adSet.getOptimizationGoal());
        body.put("budget_mode", "BUDGET_MODE_DAY");
        body.put("budget", adSet.getBudget() / apiConfig.getKztUsdRate());

        JsonNode response = executeApiCall(accessToken, "/adgroup/create/", body, JsonNode.class);
        return getResponseId(response, "adgroup_id");
    }

    public String createAd(String accessToken, String advertiserId, String tiktokAdGroupId, TargetingAd ad) {
        Map<String, Object> body = new HashMap<>();
        body.put("advertiser_id", advertiserId);
        body.put("adgroup_id", tiktokAdGroupId);
        body.put("ad_name", ad.getName());
        body.put("ad_text", ad.getPrimaryText() != null ? ad.getPrimaryText() : "");
        body.put("call_to_action_id", "DOWNLOAD"); // Placeholder CTA code
        // Skipping media logic to simplify
        
        JsonNode response = executeApiCall(accessToken, "/ad/create/", body, JsonNode.class);
        return getResponseId(response, "ad_id");
    }

    public TikTokCampaignDto getCampaignInsights(String accessToken, String advertiserId, String campaignId,
                                                 String startDate, String endDate) {
        Map<String, Object> body = new HashMap<>();
        body.put("advertiser_id", advertiserId);
        body.put("report_type", "BASIC");
        body.put("data_level", "AUCTION_CAMPAIGN");
        body.put("dimensions", List.of("campaign_id", "stat_time_day"));
        body.put("metrics", List.of("spend", "impressions", "reach", "clicks", "ctr", "cpm", "conversions"));
        body.put("start_date", startDate);
        body.put("end_date", endDate);
        body.put("filtering", List.of(Map.of("field_name", "campaign_ids", "filter_type", "IN", "filter_value", List.of(campaignId))));

        JsonNode response = executeApiCall(accessToken, "/report/integrated/get/", body, JsonNode.class);
        
        return TikTokCampaignDto.builder()
                .spend(0.0) // placeholder parsing
                .impressions(0L)
                .build();
    }

    public String getOAuthUrl(String userId) {
        return "https://business-api.tiktok.com/portal/auth?" +
                "app_id=" + apiConfig.getTiktok().getAppId() +
                "&state=" + userId +
                "&redirect_uri=" + apiConfig.getTiktok().getOauthRedirectUri();
    }

    public String exchangeCodeForToken(String authCode, String userId) {
        Map<String, Object> body = new HashMap<>();
        body.put("app_id", apiConfig.getTiktok().getAppId());
        body.put("secret", apiConfig.getTiktok().getAppSecret());
        body.put("auth_code", authCode);
        body.put("grant_type", "authorization_code");

        // The token endpoint doesn't require an access token in the header
        try {
            JsonNode response = webClient.post()
                    .uri("/oauth2/access_token/")
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(body)
                    .retrieve()
                    .bodyToMono(JsonNode.class)
                    .block();

            if (response != null && response.has("data") && response.get("data").has("access_token")) {
                String accessToken = response.get("data").get("access_token").asText();
                credentialsService.saveCredentials(userId, "TIKTOK", accessToken);
                return accessToken;
            }
            throw new TikTokApiException("Failed to extract access_token from TikTok response");
        } catch (WebClientResponseException e) {
            log.error("[TikTok API] Token exchange error: {}", e.getResponseBodyAsString());
            throw new TikTokApiException("Failed to exchange code", e);
        }
    }

    private <T> T executeApiCall(String accessToken, String uri, Object body, Class<T> responseType) {
        try {
            return webClient.post()
                    .uri(uri)
                    .header("Access-Token", accessToken)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(body)
                    .retrieve()
                    .bodyToMono(responseType)
                    .block();
        } catch (WebClientResponseException e) {
            log.error("[TikTok API] HTTP error calling {}: {}", uri, e.getResponseBodyAsString());
            throw new TikTokApiException("TikTok API Call Failed", e);
        } catch (Exception e) {
            log.error("[TikTok API] Unexpected error calling {}", uri, e);
            throw new TikTokApiException("Unexpected TikTok API Error", e);
        }
    }

    private String getResponseId(JsonNode response, String fieldName) {
        if (response != null && response.has("data") && response.get("data").has(fieldName)) {
            return response.get("data").get(fieldName).asText();
        }
        return null;
    }

    private String mapObjective(CampaignObjective objective) {
        if (objective == null) return "TRAFFIC";
        return switch (objective) {
            case LEADS -> "LEAD_GENERATION";
            case SALES -> "CONVERSIONS";
            case TRAFFIC -> "TRAFFIC";
            case AWARENESS -> "REACH";
            case ENGAGEMENT -> "VIDEO_VIEWS";
            case APP_INSTALLS -> "APP_PROMOTION";
        };
    }
}
