export interface Country {
  id: string;
  name: string;
  icon: string | null;
}

export interface Category {
  id: string;
  name: string;
  icon: string | null;
  parentId: string | null;
  children: Category[];
}

export interface TagGroup {
  id: string;
  name: string;
  icon: string | null;
  color: string | null;
  sortOrder: number;
}

export interface Tag {
  id: string;
  name: string;
  color: string | null;
  fontColor: string | null;
  group: { id: string; name: string; sortOrder: number } | null;
}

export interface Product {
  id: string;
  name: string;
  priority: number;
  image: string | null;
  price: string | null;
  country: Country;
  category: Category;
  tag: Tag | null;
  tags: Tag[];
}

export interface PaginatedProducts {
  items: Product[];
  total: number;
  page: number;
  pageSize: number;
}

export interface ProductQuery {
  countryId?: string;
  categoryId?: string;
  tagIds: string[];
  keyword?: string;
  page: number;
  pageSize: number;
}

export function resolveBackendAssetUrl(value: string | null, backendUrl: string): string | null {
  if (!value || /^(?:https?:|data:|blob:)/i.test(value)) return value;
  return new URL(value, `${backendUrl.replace(/\/$/, '')}/`).toString();
}

export function resolveCountryIdFromQuery(
  value: string | string[] | null | undefined,
  countries: Country[],
): string | undefined {
  const countryId = Array.isArray(value) ? value[0] : value;
  return countryId && countries.some((country) => country.id === countryId) ? countryId : undefined;
}

export function resolveCategoryIdFromQuery(
  value: string | string[] | null | undefined,
  categories: Category[],
): string | undefined {
  const categoryId = Array.isArray(value) ? value[0] : value;
  const containsId = (nodes: Category[]): boolean => nodes.some(
    (category) => category.id === categoryId || containsId(category.children),
  );
  return categoryId && containsId(categories) ? categoryId : undefined;
}

export function findCategoryIdByName(name: string, categories: Category[]): string | undefined {
  for (const category of categories) {
    if (category.name === name) return category.id;
    const childId = findCategoryIdByName(name, category.children);
    if (childId) return childId;
  }
  return undefined;
}

export function findCategoryIdForPodName(name: string, categories: Category[]): string | undefined {
  const rootName = name.includes('男士')
    ? '男士服装'
    : name.includes('女士')
      ? '女士服装'
      : /童装|儿童/.test(name)
        ? '儿童服装'
        : undefined;
  const root = rootName ? categories.find((category) => category.name === rootName) : undefined;
  if (!root) return findCategoryIdByName(name, categories);

  const childName = name.includes('T恤')
    ? 'T恤'
    : name.includes('裤')
      ? '裤装'
      : name.includes('卫衣')
        ? '卫衣'
        : name.includes('裙')
          ? '裙装'
          : name.includes('内衣')
            ? '内衣'
            : undefined;
  return root.children.find((category) => category.name === childName)?.id ?? root.id;
}

interface BackendCategoryNode {
  id: string;
  categoryName: string;
  categoryIcon: string | null;
  parentCategoryId: string | null;
  children: BackendCategoryNode[];
}

interface BackendCountry {
  id: string;
  countryName: string;
  countryIcon: string | null;
}

interface BackendTagGroup {
  id: string;
  groupName: string;
  groupIcon: string | null;
  groupColor: string | null;
  sortOrder: number;
}

interface BackendTag {
  id: string;
  tagName: string;
  tagColor: string | null;
  tagFontColor: string | null;
  group: { id: string; groupName: string; sortOrder: number } | null;
}

interface BackendProduct {
  goodId: string;
  goodName: string;
  goodPriority: number;
  country: { id: string; countryName: string; countryIcon: string | null };
  category: { id: string; categoryName: string; categoryIcon: string | null };
  tag: { id: string; tagName: string; tagColor: string | null; tagFontColor: string | null; group: { id: string; groupName: string; sortOrder: number } | null } | null;
  tags: { id: string; tagName: string; tagColor: string | null; tagFontColor: string | null; group: { id: string; groupName: string; sortOrder: number } | null }[];
  image: string | null;
  price: string | null;
  createdAt: string;
}

interface BackendPaginatedProducts {
  items: BackendProduct[];
  total: number;
  page: number;
  pageSize: number;
}

interface BackendEnvelope<T> {
  data: T;
  success: boolean;
}

function mapCategory(node: BackendCategoryNode, backendUrl: string): Category {
  return {
    id: node.id,
    name: node.categoryName,
    icon: resolveBackendAssetUrl(node.categoryIcon, backendUrl),
    parentId: node.parentCategoryId,
    children: node.children.map((child) => mapCategory(child, backendUrl)),
  };
}

function mapCountry(c: BackendCountry, backendUrl: string): Country {
  return {
    id: c.id,
    name: c.countryName,
    icon: resolveBackendAssetUrl(c.countryIcon, backendUrl),
  };
}

function mapTag(t: BackendTag): Tag {
  return {
    id: t.id,
    name: t.tagName,
    color: t.tagColor,
    fontColor: t.tagFontColor,
    group: t.group
      ? { id: t.group.id, name: t.group.groupName, sortOrder: t.group.sortOrder }
      : null,
  };
}

function mapTagGroup(g: BackendTagGroup): TagGroup {
  return {
    id: g.id,
    name: g.groupName,
    icon: g.groupIcon,
    color: g.groupColor,
    sortOrder: g.sortOrder,
  };
}

/** Sort tags by their group.order (admin-configured). Tags without a group go last. */
export function sortTagsByGroup(tags: Tag[]): Tag[] {
  return [...tags].sort((a, b) => {
    const ao = a.group?.sortOrder ?? Number.MAX_SAFE_INTEGER;
    const bo = b.group?.sortOrder ?? Number.MAX_SAFE_INTEGER;
    return ao - bo;
  });
}

export function selectExclusiveTagIds(selectedIds: string[], tags: Tag[], tagId: string): string[] {
  const selectedTag = tags.find((tag) => tag.id === tagId);
  if (!selectedTag) return selectedIds;
  if (selectedIds.includes(tagId)) return selectedIds.filter((id) => id !== tagId);

  const selectedGroupId = selectedTag.group?.id;
  const otherGroups = selectedIds.filter((id) => {
    const tag = tags.find((item) => item.id === id);
    return !selectedGroupId || tag?.group?.id !== selectedGroupId;
  });
  return [...otherGroups, tagId];
}

export function resolveDefaultProductFilters(
  _categories: Category[],
  _tags: Tag[],
): Pick<ProductQuery, 'categoryId' | 'tagIds'> {
  return {
    categoryId: undefined,
    tagIds: [],
  };
}

function mapProduct(p: BackendProduct, backendUrl: string): Product {
  return {
    id: p.goodId,
    name: p.goodName,
    priority: p.goodPriority,
    image: resolveBackendAssetUrl(p.image, backendUrl),
    price: p.price,
    country: mapCountry(p.country, backendUrl),
    category: {
      id: p.category.id,
      name: p.category.categoryName,
      icon: resolveBackendAssetUrl(p.category.categoryIcon, backendUrl),
      parentId: null,
      children: [],
    },
    tag: p.tag ? mapTag(p.tag) : null,
    tags: p.tags ? p.tags.map(mapTag) : [],
  };
}

export function useProductCenter() {
  const backendUrl = useRuntimeConfig().public.backendUrl;
  const categories = useState<Category[]>('pc-categories', () => []);
  const countries = useState<Country[]>('pc-countries', () => []);
  const tags = useState<Tag[]>('pc-tags', () => []);
  const tagGroups = useState<TagGroup[]>('pc-tag-groups', () => []);
  const products = useState<Product[]>('pc-products', () => []);
  const total = useState<number>('pc-total', () => 0);
  const loading = useState<boolean>('pc-loading', () => false);

  const query = reactive<ProductQuery>({
    countryId: undefined,
    categoryId: undefined,
    tagIds: [],
    keyword: undefined,
    page: 1,
    pageSize: 20,
  });

  const selectedCategory = computed<string | null>(() => query.categoryId ?? null);
  const selectedCountry = computed<string | null>(() => query.countryId ?? null);
  const selectedTagIds = computed<string[]>(() => query.tagIds);

  async function loadFilters(): Promise<void> {
    try {
      const needCats = categories.value.length === 0;
      const [tgs, grs] = await Promise.all([
        $fetch<BackendEnvelope<BackendTag[]>>('/api/backend/tags'),
        $fetch<BackendEnvelope<BackendTagGroup[]>>('/api/backend/tag-groups'),
      ]);
      tags.value = tgs.data.map(mapTag);
      tagGroups.value = grs.data.map(mapTagGroup);
      if (needCats) {
        const [cats, cos] = await Promise.all([
          $fetch<BackendEnvelope<BackendCategoryNode[]>>('/api/backend/categories'),
          $fetch<BackendEnvelope<BackendCountry[]>>('/api/backend/countries'),
        ]);
        categories.value = cats.data.map((category) => mapCategory(category, backendUrl));
        countries.value = cos.data.map((country) => mapCountry(country, backendUrl));
      }
    } catch (error) {
      console.error('Failed to load filters:', error);
    }
  }

  async function fetchProducts(options: { ignoreTags?: boolean } = {}): Promise<void> {
    loading.value = true;
    try {
      const params: Record<string, string | number> = {
        page: query.page,
        pageSize: query.pageSize,
      };
      if (query.countryId) params.countryId = query.countryId;
      if (query.categoryId) params.categoryId = query.categoryId;
      if (!options.ignoreTags && query.tagIds.length > 0) {
        const grouped = new Map<string, string[]>();
        for (const tagId of query.tagIds) {
          const groupId = tags.value.find((tag) => tag.id === tagId)?.group?.id;
          if (!groupId) continue;
          grouped.set(groupId, [...(grouped.get(groupId) ?? []), tagId]);
        }
        params.tags = JSON.stringify(
          [...grouped].map(([tagGroupId, tagIds]) => ({ tagGroupId, tagIds })),
        );
      }
      if (query.keyword?.trim()) params.keyword = query.keyword.trim();

      const response = await $fetch<BackendEnvelope<BackendPaginatedProducts>>(
        '/api/backend/goods',
        { params },
      );
      products.value = response.data.items.map((product) => mapProduct(product, backendUrl));
      total.value = response.data.total;
    } catch (error) {
      console.error('Failed to fetch products:', error);
      products.value = [];
      total.value = 0;
    } finally {
      loading.value = false;
    }
  }

  function setCategory(id: string | null): void {
    query.categoryId = id ?? undefined;
    query.page = 1;
  }

  function setCountry(id: string | null): void {
    query.countryId = id ?? undefined;
    query.page = 1;
  }

  function setTag(id: string): void {
    query.tagIds = selectExclusiveTagIds(query.tagIds, tags.value, id);
    query.page = 1;
  }

  function clearTags(): void {
    query.tagIds = [];
    query.page = 1;
  }

  function setKeyword(value: string): void {
    query.keyword = value;
    query.page = 1;
  }

  function setPage(page: number): void {
    query.page = Math.max(1, page);
  }

  function setPageSize(size: number): void {
    query.pageSize = size;
    query.page = 1;
  }

  return {
    categories,
    countries,
    tags,
    tagGroups,
    products,
    total,
    loading,
    query,
    selectedCategory,
    selectedCountry,
    selectedTagIds,
    loadFilters,
    fetchProducts,
    setCategory,
    setCountry,
    setTag,
    clearTags,
    setKeyword,
    setPage,
    setPageSize,
  };
}
