import type {
  GridFilterModel,
  GridSortModel,
} from "@mui/x-data-grid";

import { STAKEHOLDER_PAGE_SIZE } from "@/features/stakeholder/components/table/stakeholder-table-config";
import type {
  StakeholderHasUserFilterValue,
  StakeholderScreenFilters,
  StakeholderStatusFilterValue,
} from "@/features/stakeholder/components/stakeholder-filters";

export const STAKEHOLDER_SORT_FIELDS = [
  "id",
  "name",
  "coChair",
  "description",
  "createdAt",
  "updatedAt",
  "active",
  "stakeholderType",
] as const;

export type StakeholderSortField = (typeof STAKEHOLDER_SORT_FIELDS)[number];
export type StakeholderSortOrder = "asc" | "desc";

export type StakeholderListQuery = {
  page: number;
  limit: number;
  sortBy?: StakeholderSortField;
  sortOrder?: StakeholderSortOrder;
  search?: string;
  id?: number;
  active?: boolean;
  stakeholderTypeId?: number;
  name?: string;
  coChair?: string;
  description?: string;
  stakeholderTypeName?: string;
  stakeholderTypeIds?: number[];
  years?: number[];
  hasUsers?: boolean;
};

const SORT_FIELD_MAP: Record<string, StakeholderSortField> = {
  id: "id",
  name: "name",
  coChair: "coChair",
  description: "description",
  createdAt: "createdAt",
  updatedAt: "updatedAt",
  active: "active",
  stakeholderType: "stakeholderType",
};

export function mapSortModelToQuery(
  sortModel: GridSortModel,
): Pick<StakeholderListQuery, "sortBy" | "sortOrder"> {
  const first = sortModel[0];

  if (!first?.sort) {
    return {};
  }

  const sortBy = SORT_FIELD_MAP[first.field];

  if (!sortBy) {
    return {};
  }

  if (first.sort !== "asc" && first.sort !== "desc") {
    return {};
  }

  return {
    sortBy,
    sortOrder: first.sort,
  };
}

function parseBoolean(value: unknown): boolean | undefined {
  if (value === true || value === "true" || value === 1 || value === "1") {
    return true;
  }

  if (value === false || value === "false" || value === 0 || value === "0") {
    return false;
  }

  return undefined;
}

export function mapFilterModelToQuery(
  filterModel: GridFilterModel,
): Omit<
  StakeholderListQuery,
  "page" | "limit" | "sortBy" | "sortOrder" | "search"
> {
  const query: Omit<
    StakeholderListQuery,
    "page" | "limit" | "sortBy" | "sortOrder" | "search"
  > = {};

  for (const item of filterModel.items) {
    const { field, operator, value } = item;

    if (value == null || value === "") {
      continue;
    }

    switch (field) {
      case "id": {
        const numericValue = Number(value);

        if (!Number.isFinite(numericValue)) {
          break;
        }

        if (operator === "=" || operator === "equals" || operator === "is") {
          if (numericValue >= 1) {
            query.id = numericValue;
          }
        }
        break;
      }
      case "name":
        if (operator === "contains" || operator === "equals") {
          query.name = String(value);
        }
        break;
      case "coChair":
        if (operator === "contains" || operator === "equals") {
          query.coChair = String(value);
        }
        break;
      case "description":
        if (operator === "contains" || operator === "equals") {
          query.description = String(value);
        }
        break;
      case "stakeholderType":
        if (operator === "contains" || operator === "equals") {
          query.stakeholderTypeName = String(value);
        }
        break;
      case "active": {
        const active = parseBoolean(value);

        if (active !== undefined && (operator === "is" || operator === "equals" || operator === "=")) {
          query.active = active;
        }
        break;
      }
      default:
        break;
    }
  }

  return query;
}

function mapScreenFiltersToQuery(
  screenFilters: StakeholderScreenFilters,
): Pick<
  StakeholderListQuery,
  "active" | "stakeholderTypeIds" | "hasUsers"
> {
  const query: Pick<
    StakeholderListQuery,
    "active" | "stakeholderTypeIds" | "hasUsers"
  > = {};

  const activeStatuses = screenFilters.statuses.filter(
    (status): status is StakeholderStatusFilterValue =>
      status === "active" || status === "inactive",
  );

  if (activeStatuses.length === 1) {
    query.active = activeStatuses[0] === "active";
  }

  const typeIds = screenFilters.typeIds
    .map((typeId) => Number(typeId))
    .filter((typeId) => Number.isInteger(typeId) && typeId >= 1);

  if (typeIds.length > 0) {
    query.stakeholderTypeIds = typeIds;
  }

  const hasUserFilters = screenFilters.hasUsers.filter(
    (value): value is StakeholderHasUserFilterValue =>
      value === "yes" || value === "no",
  );

  if (hasUserFilters.length === 1) {
    query.hasUsers = hasUserFilters[0] === "yes";
  }

  return query;
}

export function buildStakeholderListQuery({
  page,
  limit,
  search,
  sortModel,
  filterModel,
  screenFilters,
}: {
  page: number;
  limit: number;
  search?: string;
  sortModel: GridSortModel;
  filterModel: GridFilterModel;
  screenFilters?: StakeholderScreenFilters;
}): StakeholderListQuery {
  const trimmedSearch = search?.trim();
  const safePage = Number.isFinite(page) && page >= 1 ? page : 1;
  const safeLimit =
    Number.isFinite(limit) && limit >= 1
      ? Math.min(limit, 100)
      : STAKEHOLDER_PAGE_SIZE;

  return {
    page: safePage,
    limit: safeLimit,
    ...(trimmedSearch ? { search: trimmedSearch.slice(0, 200) } : {}),
    ...mapSortModelToQuery(sortModel),
    ...mapFilterModelToQuery(filterModel),
    ...(screenFilters ? mapScreenFiltersToQuery(screenFilters) : {}),
  };
}
