"use client";
import * as React from "react";
import { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
import { resolveTodoApiPath } from "../utils.js";
import { generateTempId } from "@open-mercato/core/modules/customers/lib/detailHelpers";
import { parseBooleanToken } from "@open-mercato/shared/lib/boolean";
import { CUSTOMER_INTERACTION_TASK_SOURCE } from "../../../lib/interactionCompatibility.js";
const DEFAULT_TODO_SOURCE = CUSTOMER_INTERACTION_TASK_SOURCE;
function mapRowToSummary(row) {
  return {
    id: row.id,
    todoId: row.todoId,
    todoSource: row.todoSource || DEFAULT_TODO_SOURCE,
    createdAt: row.createdAt,
    title: row.todoTitle ?? null,
    isDone: row.todoIsDone ?? null,
    status: row.todoIsDone ? "done" : "planned",
    priority: row.todoPriority ?? null,
    severity: row.todoSeverity ?? null,
    description: row.todoDescription ?? null,
    dueAt: row.todoDueAt ?? null,
    todoOrganizationId: row.todoOrganizationId ?? null,
    updatedAt: row.todoUpdatedAt ?? null,
    customValues: row.todoCustomValues ?? null
  };
}
function mergeUnique(existing, incoming) {
  if (!existing.length) return incoming;
  if (!incoming.length) return existing;
  const byId = /* @__PURE__ */ new Map();
  const result = [];
  for (const item of existing) {
    byId.set(item.id, item);
    result.push(item);
  }
  for (const item of incoming) {
    if (byId.has(item.id)) {
      const index = result.findIndex((entry) => entry.id === item.id);
      if (index !== -1) result[index] = item;
    } else {
      byId.set(item.id, item);
      result.push(item);
    }
  }
  return result;
}
function normalizeBoolean(value) {
  if (value === null || value === void 0) return void 0;
  if (typeof value === "boolean") return value;
  if (typeof value === "string") {
    const parsed = parseBooleanToken(value);
    return parsed === null ? void 0 : parsed;
  }
  return void 0;
}
function normalizeNumber(value) {
  if (value === null || value === void 0 || value === "") return void 0;
  if (typeof value === "number" && Number.isFinite(value)) return value;
  if (typeof value === "string") {
    const trimmed = value.trim();
    if (!trimmed.length) return void 0;
    const parsed = Number(trimmed);
    if (!Number.isNaN(parsed)) return parsed;
  }
  return null;
}
function normalizeString(value) {
  if (value === null || value === void 0) return void 0;
  if (typeof value === "string") {
    const trimmed = value.trim();
    return trimmed.length ? trimmed : null;
  }
  return String(value);
}
function buildLegacyTaskCustomValues(payload, options) {
  const includeEmptyFields = options?.includeEmptyFields === true;
  const custom = { ...payload.custom };
  const assignValue = (key, value) => {
    if (value === void 0) return;
    if (value === null) {
      if (includeEmptyFields) custom[key] = null;
      return;
    }
    custom[key] = value;
  };
  assignValue("priority", payload.base.priority ?? null);
  assignValue("description", payload.base.description ?? null);
  assignValue("due_at", payload.base.scheduledAt ?? null);
  return custom;
}
function usePersonTasks({
  entityId,
  initialTasks = [],
  pageSize = 20
}) {
  const [tasks, setTasks] = React.useState(initialTasks);
  const [pageInfo, setPageInfo] = React.useState({
    page: 1,
    totalPages: 1,
    total: initialTasks.length
  });
  const [isInitialLoading, setIsInitialLoading] = React.useState(() => Boolean(entityId));
  const [isLoadingMore, setIsLoadingMore] = React.useState(false);
  const [isMutating, setIsMutating] = React.useState(false);
  const [pendingTaskId, setPendingTaskId] = React.useState(null);
  const [error, setError] = React.useState(null);
  const mapResponse = React.useCallback((payload) => {
    const mapped = Array.isArray(payload.items) ? payload.items.map(mapRowToSummary) : [];
    setPageInfo({
      page: payload.page ?? 1,
      totalPages: payload.totalPages ?? 0,
      total: payload.total ?? mapped.length
    });
    setError(null);
    return mapped;
  }, []);
  const fetchPage = React.useCallback(
    async (page) => {
      if (!entityId) {
        return {
          items: [],
          total: 0,
          page: 1,
          pageSize,
          totalPages: 1
        };
      }
      const params = new URLSearchParams({
        page: String(page),
        pageSize: String(pageSize),
        entityId
      });
      return readApiResultOrThrow(
        `/api/customers/todos?${params.toString()}`,
        void 0,
        { errorMessage: "Failed to load tasks." }
      );
    },
    [entityId, pageSize]
  );
  const refresh = React.useCallback(async () => {
    if (!entityId) {
      setTasks([]);
      setPageInfo({ page: 1, totalPages: 1, total: 0 });
      return;
    }
    setIsInitialLoading(true);
    try {
      const payload = await fetchPage(1);
      const mapped = mapResponse(payload);
      setTasks(mapped);
    } catch (err) {
      const message = err instanceof Error ? err.message : "Failed to load tasks.";
      setError(message);
      throw err;
    } finally {
      setIsInitialLoading(false);
    }
  }, [entityId, fetchPage, mapResponse]);
  const loadMore = React.useCallback(async () => {
    if (!entityId) return;
    if (isLoadingMore) return;
    if (pageInfo.page >= pageInfo.totalPages) return;
    setIsLoadingMore(true);
    try {
      const payload = await fetchPage(pageInfo.page + 1);
      const mapped = mapResponse(payload);
      setTasks((prev) => mergeUnique(prev, mapped));
    } catch (err) {
      const message = err instanceof Error ? err.message : "Failed to load tasks.";
      setError(message);
      throw err;
    } finally {
      setIsLoadingMore(false);
    }
  }, [entityId, fetchPage, isLoadingMore, mapResponse, pageInfo.page, pageInfo.totalPages]);
  React.useEffect(() => {
    if (!entityId) {
      setTasks([]);
      setPageInfo({ page: 1, totalPages: 1, total: 0 });
      setError(null);
      setIsInitialLoading(false);
      return;
    }
    setTasks(initialTasks);
    setPageInfo({
      page: 1,
      totalPages: 1,
      total: initialTasks.length
    });
    setError(null);
    let cancelled = false;
    setIsInitialLoading(true);
    fetchPage(1).then((payload) => {
      if (cancelled) return;
      const mapped = mapResponse(payload);
      setTasks(mapped);
    }).catch((err) => {
      if (cancelled) return;
      const message = err instanceof Error ? err.message : "Failed to load tasks.";
      setError(message);
    }).finally(() => {
      if (!cancelled) setIsInitialLoading(false);
    });
    return () => {
      cancelled = true;
    };
  }, [entityId, initialTasks, fetchPage, mapResponse]);
  const createTask = React.useCallback(
    async ({ base, custom }) => {
      if (!entityId) throw new Error("Task creation requires an entity id");
      setIsMutating(true);
      try {
        const customValues = buildLegacyTaskCustomValues({ base, custom });
        const payload = {
          entityId,
          title: base.title
        };
        const normalizedDone = normalizeBoolean(base.is_done);
        if (normalizedDone !== void 0) payload.isDone = normalizedDone;
        if (Object.keys(customValues).length) payload.todoCustom = customValues;
        const response = await apiCallOrThrow(
          "/api/customers/todos",
          {
            method: "POST",
            headers: { "content-type": "application/json" },
            body: JSON.stringify(payload)
          },
          { errorMessage: "Failed to create task." }
        );
        const body = response.result ?? {};
        const linkId = typeof body.linkId === "string" && body.linkId.length ? body.linkId : generateTempId();
        const todoId = typeof body.todoId === "string" && body.todoId.length ? body.todoId : generateTempId();
        const createdAt = (/* @__PURE__ */ new Date()).toISOString();
        const persistedCustomValues = Object.keys(customValues).length ? { ...customValues } : null;
        const priority = normalizeNumber(base.priority ?? customValues.priority);
        const severity = normalizeString(customValues.severity) ?? null;
        const description = normalizeString(base.description ?? customValues.description) ?? null;
        const newTask = {
          id: linkId,
          todoId,
          todoSource: DEFAULT_TODO_SOURCE,
          createdAt,
          title: base.title,
          isDone: normalizedDone ?? false,
          status: normalizedDone ? "done" : "planned",
          priority: priority === void 0 ? null : priority,
          severity,
          description,
          dueAt: normalizeString(base.scheduledAt ?? customValues.due_at) ?? normalizeString(customValues.dueAt) ?? null,
          todoOrganizationId: null,
          customValues: persistedCustomValues
        };
        setTasks((prev) => [newTask, ...prev]);
        setPageInfo((prev) => ({
          page: 1,
          totalPages: prev.totalPages,
          total: prev.total + 1
        }));
        await refresh();
      } finally {
        setIsMutating(false);
      }
    },
    [entityId, refresh]
  );
  const updateTask = React.useCallback(
    async (task, { base, custom }) => {
      if (!task.todoId) throw new Error("Task is missing todo id");
      const apiPath = resolveTodoApiPath(task.todoSource || DEFAULT_TODO_SOURCE);
      if (!apiPath) throw new Error("Unsupported task source");
      setIsMutating(true);
      try {
        const customValues = buildLegacyTaskCustomValues({ base, custom }, { includeEmptyFields: true });
        const body = {
          id: task.todoId,
          linkId: task.id
        };
        if (typeof base.title === "string" && base.title.trim().length) {
          body.title = base.title.trim();
        }
        const normalizedDone = normalizeBoolean(base.is_done);
        if (normalizedDone !== void 0) body.is_done = normalizedDone;
        if (Object.keys(customValues).length) {
          body.customFields = customValues;
        }
        await withScopedApiRequestHeaders(
          buildOptimisticLockHeader(task.updatedAt ?? null),
          () => apiCallOrThrow(
            apiPath,
            {
              method: "PUT",
              headers: { "content-type": "application/json" },
              body: JSON.stringify(body)
            },
            { errorMessage: "Failed to update task." }
          )
        );
        setTasks(
          (prev) => prev.map((item) => {
            if (item.id !== task.id) return item;
            const nextCustomValues = { ...item.customValues ?? {} };
            for (const [key, value] of Object.entries(customValues)) {
              nextCustomValues[key] = value === void 0 ? null : value;
            }
            return {
              ...item,
              title: typeof base.title === "string" && base.title.trim().length ? base.title.trim() : item.title,
              isDone: normalizedDone !== void 0 ? normalizedDone : item.isDone,
              status: normalizedDone !== void 0 ? normalizedDone ? "done" : "planned" : item.status ?? null,
              priority: normalizeNumber(base.priority ?? customValues.priority) ?? (base.priority === void 0 && customValues.priority === void 0 ? item.priority ?? null : null),
              severity: normalizeString(customValues.severity) ?? (customValues.severity === void 0 ? item.severity ?? null : null),
              description: normalizeString(base.description ?? customValues.description) ?? (base.description === void 0 && customValues.description === void 0 ? item.description ?? null : null),
              dueAt: normalizeString(base.scheduledAt ?? customValues.due_at) ?? normalizeString(customValues.dueAt) ?? (base.scheduledAt === void 0 && customValues.due_at === void 0 && customValues.dueAt === void 0 ? item.dueAt ?? null : null),
              customValues: Object.keys(nextCustomValues).length ? nextCustomValues : null
            };
          })
        );
      } finally {
        setIsMutating(false);
      }
    },
    []
  );
  const toggleTask = React.useCallback(
    async (task, nextIsDone) => {
      if (!task.todoId) {
        throw new Error("Task is missing todo id");
      }
      const apiPath = resolveTodoApiPath(task.todoSource || DEFAULT_TODO_SOURCE);
      if (!apiPath) {
        throw new Error("Unsupported task source");
      }
      setPendingTaskId(task.todoId);
      try {
        await updateTask(task, { base: { title: task.title ?? "", is_done: nextIsDone }, custom: {} });
      } finally {
        setPendingTaskId(null);
      }
    },
    [updateTask]
  );
  const unlinkTask = React.useCallback(
    async (task) => {
      if (!task.id) throw new Error("Task link id missing");
      setIsMutating(true);
      try {
        await withScopedApiRequestHeaders(
          buildOptimisticLockHeader(task.updatedAt ?? null),
          () => apiCallOrThrow(
            "/api/customers/todos",
            {
              method: "DELETE",
              headers: { "content-type": "application/json" },
              body: JSON.stringify({ id: task.id })
            },
            { errorMessage: "Failed to remove task." }
          )
        );
        setTasks((prev) => prev.filter((item) => item.id !== task.id));
        setPageInfo((prev) => ({
          page: prev.page,
          totalPages: prev.totalPages,
          total: Math.max(0, prev.total - 1)
        }));
      } finally {
        setIsMutating(false);
      }
    },
    []
  );
  const hasMore = entityId != null && pageInfo.page < pageInfo.totalPages;
  return {
    tasks,
    isInitialLoading,
    isLoadingMore,
    isMutating,
    hasMore,
    loadMore,
    refresh,
    createTask,
    updateTask,
    toggleTask,
    unlinkTask,
    pendingTaskId,
    totalCount: pageInfo.total,
    error
  };
}
export {
  usePersonTasks
};
//# sourceMappingURL=usePersonTasks.js.map
