import { ProcurementMaterial } from '@/types';
import { normalizeEmptyFieldText } from '@/lib/emptyFieldPlaceholders';
import { getSupabaseClient } from '@/lib/supabase';
import { filterKnownTestMaterials } from '@/lib/materialFilters';

export type ProcurementMaterialInsert = Omit<ProcurementMaterial, 'id' | 'created_at'>;

function looksLikeUuid(value: string) {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
}

async function hydrateMaterialCreators(materials: ProcurementMaterial[]): Promise<ProcurementMaterial[]> {
  const creatorIds = [...new Set(
    materials
      .map((material) => material.created_by)
      .filter((value): value is string => typeof value === 'string' && looksLikeUuid(value)),
  )];

  if (creatorIds.length === 0) {
    return materials;
  }

  const supabase = getSupabaseClient();
  const { data, error } = await supabase
    .from('profiles')
    .select('id, username')
    .in('id', creatorIds);

  if (error) {
    console.warn('Failed to resolve material creator usernames:', error);
    return materials;
  }

  const usernameById = new Map(
    (data ?? []).map((profile) => [String(profile.id), String(profile.username)]),
  );

  return materials.map((material) => ({
    ...material,
    created_by: material.created_by ? (usernameById.get(material.created_by) ?? material.created_by) : material.created_by,
  }));
}

function normalizeProcurementMaterial(
  material: ProcurementMaterial,
): ProcurementMaterial {
  return {
    ...material,
    material_name: normalizeEmptyFieldText(material.material_name),
    specification: normalizeEmptyFieldText(material.specification),
    unit: normalizeEmptyFieldText(material.unit),
    technical_standard: normalizeEmptyFieldText(material.technical_standard),
    material_requirement: normalizeEmptyFieldText(material.material_requirement),
    technical_requirement: normalizeEmptyFieldText(material.technical_requirement),
    applicable_conditions: normalizeEmptyFieldText(material.applicable_conditions),
    test_requirement: normalizeEmptyFieldText(material.test_requirement),
    acceptance_note: normalizeEmptyFieldText(material.acceptance_note),
    warranty_period: normalizeEmptyFieldText(material.warranty_period),
    deadline: normalizeEmptyFieldText(material.deadline),
    invoice_type: normalizeEmptyFieldText(material.invoice_type),
    brand: normalizeEmptyFieldText(material.brand),
    remarks: normalizeEmptyFieldText(material.remarks),
    delivery_address: normalizeEmptyFieldText(material.delivery_address),
  };
}

function normalizeProcurementMaterialInsert(
  material: ProcurementMaterialInsert,
): ProcurementMaterialInsert {
  return {
    ...material,
    material_name: normalizeEmptyFieldText(material.material_name),
    specification: normalizeEmptyFieldText(material.specification),
    unit: normalizeEmptyFieldText(material.unit),
    technical_standard: normalizeEmptyFieldText(material.technical_standard),
    material_requirement: normalizeEmptyFieldText(material.material_requirement),
    technical_requirement: normalizeEmptyFieldText(material.technical_requirement),
    applicable_conditions: normalizeEmptyFieldText(material.applicable_conditions),
    test_requirement: normalizeEmptyFieldText(material.test_requirement),
    acceptance_note: normalizeEmptyFieldText(material.acceptance_note),
    warranty_period: normalizeEmptyFieldText(material.warranty_period),
    deadline: normalizeEmptyFieldText(material.deadline),
    invoice_type: normalizeEmptyFieldText(material.invoice_type),
    brand: normalizeEmptyFieldText(material.brand),
    remarks: normalizeEmptyFieldText(material.remarks),
    delivery_address: normalizeEmptyFieldText(material.delivery_address),
  };
}

export async function fetchMaterials(params?: {
  batchId?: string;
  search?: string;
}): Promise<ProcurementMaterial[]> {
  const supabase = getSupabaseClient();
  let query = supabase
    .from('procurement_materials')
    .select('*')
    .order('created_at', { ascending: true });

  if (params?.batchId) {
    query = query.eq('batch_id', params.batchId);
  }
  if (params?.search) {
    query = query.ilike('material_name', `%${params.search}%`);
  }

  const { data, error } = await query;
  if (error) throw new Error(error.message);
  const materials = filterKnownTestMaterials((data ?? []) as ProcurementMaterial[])
    .map(normalizeProcurementMaterial);
  return hydrateMaterialCreators(materials);
}

export async function fetchMaterialById(id: string): Promise<ProcurementMaterial | undefined> {
  const supabase = getSupabaseClient();
  const { data, error } = await supabase
    .from('procurement_materials')
    .select('*')
    .eq('id', id)
    .maybeSingle();

  if (error) throw new Error(error.message);
  if (!data) {
    return undefined;
  }

  const [material] = await hydrateMaterialCreators([normalizeProcurementMaterial(data as ProcurementMaterial)]);
  return material;
}

export async function createMaterials(materials: ProcurementMaterialInsert[]): Promise<ProcurementMaterial[]> {
  if (materials.length === 0) {
    return [];
  }

  const normalizedMaterials = materials.map(normalizeProcurementMaterialInsert);
  const supabase = getSupabaseClient();
  const { data, error } = await supabase
    .from('procurement_materials')
    .insert(normalizedMaterials)
    .select('*');

  if (error) throw new Error(error.message);

  return hydrateMaterialCreators(((data ?? []) as ProcurementMaterial[]).map(normalizeProcurementMaterial));
}

export async function updateMaterial(
  id: string,
  updates: Partial<Omit<ProcurementMaterial, 'id' | 'created_at'>>,
): Promise<ProcurementMaterial> {
  const normalizedUpdates = Object.fromEntries(
    Object.entries(updates).map(([key, value]) => {
      if (typeof value !== 'string') {
        return [key, value];
      }

      return [key, normalizeEmptyFieldText(value)];
    }),
  ) as Partial<Omit<ProcurementMaterial, 'id' | 'created_at'>>;

  const supabase = getSupabaseClient();
  const { data, error } = await supabase
    .from('procurement_materials')
    .update(normalizedUpdates)
    .eq('id', id)
    .select('*')
    .single();

  if (error) throw new Error(error.message);
  const [material] = await hydrateMaterialCreators([normalizeProcurementMaterial(data as ProcurementMaterial)]);
  return material;
}

export async function deleteMaterialById(id: string): Promise<void> {
  const supabase = getSupabaseClient();
  const { data, error } = await supabase
    .from('procurement_materials')
    .delete()
    .eq('id', id)
    .select('id')
    .maybeSingle();

  if (error) throw new Error(error.message);
  if (!data) {
    throw new Error('材料删除失败：未找到记录或当前账号没有删除权限。');
  }
}

export async function deleteMaterialsByIds(ids: string[]): Promise<void> {
  if (ids.length === 0) {
    return;
  }

  const supabase = getSupabaseClient();
  const { data, error } = await supabase
    .from('procurement_materials')
    .delete()
    .in('id', ids)
    .select('id');

  if (error) throw new Error(error.message);
  if ((data?.length ?? 0) === 0) {
    throw new Error('采购清单回滚删除失败。');
  }
}
