import axios from "axios";
import { logger } from "./logger";
import { Observation, Event, TaskLog, InventoryMovement } from "./types";

function authHeaders() {
  const token = process.env.FARMOS_TOKEN;
  if (token) {
    return { Authorization: `Bearer ${token}` };
  }
  const user = process.env.FARMOS_USER;
  const pass = process.env.FARMOS_PASSWORD;
  if (user && pass) {
    const basic = Buffer.from(`${user}:${pass}`).toString("base64");
    return { Authorization: `Basic ${basic}` };
  }
  return {};
}

const baseUrl = process.env.FARMOS_BASE_URL || "http://localhost:8080";

async function postJsonApi(path: string, data: any, trace_id?: string) {
  const url = `${baseUrl}${path}`;
  const headers: any = {
    "Content-Type": "application/vnd.api+json",
    ...authHeaders()
  };
  if (trace_id) {
    headers["X-AGX-TRACE-ID"] = trace_id;
  }
  const resp = await axios.post(url, data, { headers, timeout: 20000 });
  return resp.data;
}

function assetRelationship(assetId?: string) {
  if (!assetId) return undefined;
  return {
    asset: { data: [{ type: "asset--asset", id: assetId }] }
  };
}

export async function writeObservation(obs: Observation, trace_id?: string, dedup_key?: string) {
  if (!process.env.FARMOS_TOKEN && !process.env.FARMOS_USER) {
    logger.warn("farmOS credentials missing, skipping write")
    return null;
  }
  const payload = {
    data: {
      type: "log--observation",
      attributes: {
        name: `${obs.metric}`,
        timestamp: new Date(obs.ts).toISOString(),
        status: "done",
        notes: `${obs.value}`
      },
      relationships: assetRelationship(obs.assetRef.assetId)
    }
  };
  const start = Date.now();
  try {
    const res = await postJsonApi("/jsonapi/log/observation", payload, trace_id);
    logger.info({ trace_id, dedup_key, farmos_endpoint: "/jsonapi/log/observation", attempt: 1, duration_ms: Date.now() - start, success: true }, "farmos_write");
    return res;
  } catch (e: any) {
    logger.error({ trace_id, dedup_key, farmos_endpoint: "/jsonapi/log/observation", attempt: 1, duration_ms: Date.now() - start, success: false, error: e.message }, "farmos_write_failed");
    throw e;
  }
}

export async function writeEvent(evt: Event, trace_id?: string, dedup_key?: string) {
  const payload = {
    data: {
      type: "log--activity",
      attributes: {
        name: evt.type,
        timestamp: new Date(evt.ts).toISOString(),
        status: "done",
        notes: evt.payload ? JSON.stringify(evt.payload) : ""
      },
      relationships: assetRelationship(evt.assetRef.assetId)
    }
  };
  const start = Date.now();
  try {
    const res = await postJsonApi("/jsonapi/log/activity", payload, trace_id);
    logger.info({ trace_id, dedup_key, farmos_endpoint: "/jsonapi/log/activity", attempt: 1, duration_ms: Date.now() - start, success: true }, "farmos_write");
    return res;
  } catch (e: any) {
    logger.error({ trace_id, dedup_key, farmos_endpoint: "/jsonapi/log/activity", attempt: 1, duration_ms: Date.now() - start, success: false, error: e.message }, "farmos_write_failed");
    throw e;
  }
}

export async function writeTaskLog(task: TaskLog, trace_id?: string, dedup_key?: string) {
  const payload = {
    data: {
      type: "log--task",
      attributes: {
        name: task.task,
        timestamp: new Date(task.ts).toISOString(),
        status: task.status,
        notes: task.notes || ""
      },
      relationships: assetRelationship(task.assetRef.assetId)
    }
  };
  const start = Date.now();
  try {
    const res = await postJsonApi("/jsonapi/log/task", payload, trace_id);
    logger.info({ trace_id, dedup_key, farmos_endpoint: "/jsonapi/log/task", attempt: 1, duration_ms: Date.now() - start, success: true }, "farmos_write");
    return res;
  } catch (e: any) {
    logger.error({ trace_id, dedup_key, farmos_endpoint: "/jsonapi/log/task", attempt: 1, duration_ms: Date.now() - start, success: false, error: e.message }, "farmos_write_failed");
    throw e;
  }
}

export async function writeInventoryMovement(mov: InventoryMovement, trace_id?: string, dedup_key?: string) {
  const payload = {
    data: {
      type: "log--inventory",
      attributes: {
        name: mov.item,
        timestamp: new Date(mov.ts).toISOString(),
        status: "done",
        notes: `${mov.direction} ${mov.quantity} ${mov.unit || ""}`.trim()
      },
      relationships: assetRelationship(mov.assetRef.assetId)
    }
  };
  const start = Date.now();
  try {
    const res = await postJsonApi("/jsonapi/log/inventory", payload, trace_id);
    logger.info({ trace_id, dedup_key, farmos_endpoint: "/jsonapi/log/inventory", attempt: 1, duration_ms: Date.now() - start, success: true }, "farmos_write");
    return res;
  } catch (e: any) {
    logger.error({ trace_id, dedup_key, farmos_endpoint: "/jsonapi/log/inventory", attempt: 1, duration_ms: Date.now() - start, success: false, error: e.message }, "farmos_write_failed");
    throw e;
  }
}
