/**
 * Crop Zoning API
 * @see CROP_ZONING_APIS.md
 */

import type { Feature, FeatureCollection, Polygon } from "geojson";
import { apiClient } from "../client";
import type {
  RecommendationTaskInitResponse,
  RecommendationTaskStatus,
  RecommendationTaskStatusResponse,
} from "./recommendationTask";
import { normalizeRecommendationTaskStatus } from "./recommendationTask";

const PREFIX = "/api/crop-zoning";
const AREA_CACHE_KEY_PREFIX = "crop-zoning:area";
const AREA_CACHE_VERSION = "v1";
const AREA_CACHE_TTL_MS = 1000 * 60 * 60 * 6;

export interface Product {
  id: string;
  label: string;
  color: string;
}

export interface ZoneInitialData {
  zoneId: string;
  zoneUuid?: string;
  geometry: Polygon;
  center?: {
    latitude: number;
    longitude: number;
  };
  area_sqm?: number;
  area_hectares?: number;
  sequence?: number;
  processing_status?: "pending" | "processing" | "completed" | "failed";
  processing_error?: string;
  /** اگر null/خالی/uncultivable باشد، زون غیرقابل کشت و خاکستری نمایش داده می‌شود */
  crop?: string | null;
  matchPercent?: number | null;
  waterNeed?: string | null;
  estimatedProfit?: string | null;
  waterNeedLayer?: {
    level: "low" | "medium" | "high";
    value?: string;
    color: string;
  };
  soilQualityLayer?: {
    level: "low" | "medium" | "high";
    score?: number;
    color: string;
  };
  cultivationRiskLayer?: {
    level: "low" | "medium" | "high";
    color: string;
  };
}

export interface ZonesInitialResponse {
  total_area_hectares: number;
  total_area_sqm: number;
  zone_count: number;
  zones: ZoneInitialData[];
}

export interface AreaResponse {
  area: Feature<Polygon> | null;
}

export interface CropZoningAreaTask {
  status?:
    | "IDLE"
    | "PENDING"
    | "PROCESSING"
    | "SUCCESS"
    | "FAILURE"
    | "pending"
    | "processing"
    | "success"
    | "completed"
    | "failure"
    | "failed";
  stage?: string;
  stage_label?: string;
  area_uuid?: string;
  total_zones?: number;
  completed_zones?: number;
  processing_zones?: number;
  pending_zones?: number;
  failed_zones?: number;
  remaining_zones?: number;
  progress_percent?: number;
  message?: string;
  failed_zone_errors?: string[];
  cell_side_km?: number;
}

export interface CropZoningAreaResult extends AreaResponse {
  status?: string;
  task?: CropZoningAreaTask | null;
  zones?: ZoneInitialData[];
  pagination?: {
    page: number;
    page_size: number;
    total_pages: number;
    total_zones: number;
    returned_zones: number;
    has_next: boolean;
    has_previous: boolean;
  };
}

export type CropZoningAreaResponse =
  | CropZoningAreaResult
  | RecommendationTaskInitResponse;

export interface ZoneDetailData {
  zoneId: string;
  crop: string;
  matchPercent: number;
  waterNeed: string;
  estimatedProfit: string;
  reason: string;
  criteria: { name: string; value: number }[];
  area_hectares?: number;
}

/** دیتای نیاز آبی هر زون — لایهٔ نیاز آبی */
export interface ZoneWaterNeedData {
  zoneId: string;
  geometry: Polygon;
  level: "low" | "medium" | "high";
  value?: string;
  color: string;
}

/** دیتای کیفیت خاک هر زون — لایهٔ کیفیت خاک */
export interface ZoneSoilQualityData {
  zoneId: string;
  geometry: Polygon;
  level: "low" | "medium" | "high";
  score?: number;
  color: string;
}

/** دیتای ریسک کشت هر زون — لایهٔ ریسک کشت */
export interface ZoneCultivationRiskData {
  zoneId: string;
  geometry: Polygon;
  level: "low" | "medium" | "high";
  color: string;
}

/** دادهٔ نمایشی هر زون روی نقشه — خروجی تبدیل از تمام لایه‌ها */
export interface ZoneMapData {
  zoneId: string;
  geometry: Polygon;
  color: string;
  tooltipContent: string;
  cultivable: boolean;
  zoneInitialData?: ZoneInitialData;
}

interface ApiResponse<T> {
  status: string;
  data: T;
}

interface CachedAreaEntry {
  expiresAt: number;
  value: CropZoningAreaResult;
}

async function unwrap<T>(promise: Promise<ApiResponse<T>>): Promise<T> {
  const res = await promise;
  return res.data;
}

function normalizeTaskInitResponse(
  task: RecommendationTaskInitResponse,
): RecommendationTaskInitResponse {
  return {
    ...task,
    status: normalizeRecommendationTaskStatus(task.status),
  };
}

function normalizeAreaResult(
  result: CropZoningAreaResult,
): CropZoningAreaResult {
  return {
    ...result,
    task: result.task
      ? {
          ...result.task,
          status: normalizeRecommendationTaskStatus(result.task.status),
        }
      : result.task,
  };
}

function getAreaCacheUserKey(): string {
  if (typeof window === "undefined") return "server";

  const token = localStorage.getItem("auth_token");

  if (!token) {
    return "guest";
  }

  try {
    return btoa(token).slice(0, 24);
  } catch {
    return token.slice(0, 24);
  }
}

function getAreaCacheKey(
  sensorUuid: string,
  page: number,
  pageSize: number,
): string {
  return [
    AREA_CACHE_KEY_PREFIX,
    AREA_CACHE_VERSION,
    getAreaCacheUserKey(),
    sensorUuid,
    page,
    pageSize,
  ].join(":");
}

function readCachedArea(
  sensorUuid: string,
  page: number,
  pageSize: number,
): CropZoningAreaResult | null {
  if (typeof window === "undefined") return null;

  try {
    const raw = localStorage.getItem(getAreaCacheKey(sensorUuid, page, pageSize));

    if (!raw) {
      return null;
    }

    const parsed = JSON.parse(raw) as CachedAreaEntry;

    if (!parsed?.expiresAt || parsed.expiresAt < Date.now()) {
      localStorage.removeItem(getAreaCacheKey(sensorUuid, page, pageSize));
      return null;
    }

    return normalizeAreaResult(parsed.value);
  } catch {
    return null;
  }
}

function writeCachedArea(
  sensorUuid: string,
  page: number,
  pageSize: number,
  value: CropZoningAreaResult,
): void {
  if (typeof window === "undefined") return;

  try {
    const payload: CachedAreaEntry = {
      expiresAt: Date.now() + AREA_CACHE_TTL_MS,
      value,
    };

    localStorage.setItem(
      getAreaCacheKey(sensorUuid, page, pageSize),
      JSON.stringify(payload),
    );
  } catch {
    // Ignore storage quota and serialization errors.
  }
}

export const cropZoningService = {
  getProducts(): Promise<{ products: Product[] }> {
    return unwrap(
      apiClient.get<ApiResponse<{ products: Product[] }>>(
        `${PREFIX}/products/`,
      ),
    );
  },

  getZonesInitial(body: {
    zones: FeatureCollection<Polygon>;
    products?: string[];
  }): Promise<ZonesInitialResponse> {
    return unwrap(
      apiClient.post<ApiResponse<ZonesInitialResponse>>(
        `${PREFIX}/zones/initial/`,
        body,
      ),
    );
  },

  getZoneDetails(zoneId: string): Promise<ZoneDetailData> {
    return unwrap(
      apiClient.get<ApiResponse<ZoneDetailData>>(
        `${PREFIX}/zones/${zoneId}/details/`,
      ),
    );
  },

  getArea(
    sensorUuid: string,
    options?: { page?: number; pageSize?: number; useCache?: boolean },
  ): Promise<CropZoningAreaResponse> {
    const page = options?.page ?? 1;
    const pageSize = options?.pageSize ?? 10;
    const useCache = options?.useCache ?? true;

    if (useCache) {
      const cached = readCachedArea(sensorUuid, page, pageSize);

      if (cached) {
        return Promise.resolve(cached);
      }
    }

    const params = new URLSearchParams({ sensor_uuid: sensorUuid });

    params.set("page", String(page));
    params.set("page_size", String(pageSize));

    return unwrap(
      apiClient.get<ApiResponse<CropZoningAreaResponse>>(
        `${PREFIX}/area/?${params.toString()}`,
      ),
    ).then((response) => {
      if ("task_id" in response) {
        return normalizeTaskInitResponse(response);
      }

      const normalized = normalizeAreaResult(response);
      const taskStatus = normalized.task?.status?.toLowerCase();

      if (
        normalized.area &&
        taskStatus !== "pending" &&
        taskStatus !== "processing" &&
        taskStatus !== "failure" &&
        taskStatus !== "failed"
      ) {
        writeCachedArea(sensorUuid, page, pageSize, normalized);
      }

      return normalized;
    });
  },

  getAreaStatus(
    taskId: string,
  ): Promise<RecommendationTaskStatusResponse<CropZoningAreaResult>> {
    return unwrap(
      apiClient.get<
        ApiResponse<RecommendationTaskStatusResponse<CropZoningAreaResult>>
      >(`${PREFIX}/area/status/${taskId}/`),
    ).then((response) => ({
      ...response,
      status: normalizeRecommendationTaskStatus(response.status),
      result: response.result
        ? normalizeAreaResult(response.result)
        : undefined,
    }));
  },

  /** نیاز آبی هر منطقه — برای لایهٔ نیاز آبی */
  getZonesWaterNeed(body: {
    zones: FeatureCollection<Polygon>;
  }): Promise<{ zones: ZoneWaterNeedData[] }> {
    return unwrap(
      apiClient.post<ApiResponse<{ zones: ZoneWaterNeedData[] }>>(
        `${PREFIX}/zones/water-need/`,
        body,
      ),
    );
  },

  /** کیفیت خاک هر منطقه — برای لایهٔ کیفیت خاک */
  getZonesSoilQuality(body: {
    zones: FeatureCollection<Polygon>;
  }): Promise<{ zones: ZoneSoilQualityData[] }> {
    return unwrap(
      apiClient.post<ApiResponse<{ zones: ZoneSoilQualityData[] }>>(
        `${PREFIX}/zones/soil-quality/`,
        body,
      ),
    );
  },

  /** ریسک کشت هر منطقه — برای لایهٔ ریسک کشت */
  getZonesCultivationRisk(body: {
    zones: FeatureCollection<Polygon>;
  }): Promise<{ zones: ZoneCultivationRiskData[] }> {
    return unwrap(
      apiClient.post<ApiResponse<{ zones: ZoneCultivationRiskData[] }>>(
        `${PREFIX}/zones/cultivation-risk/`,
        body,
      ),
    );
  },
};
