import { z } from 'zod';
import { CompanyDatabase } from '../database/db.js';
import { BrregClient } from '../apis/brreg.js';
const SearchCompaniesSchema = z.object({
industry: z.string().optional().describe("Bransje/NACE-kode (f.eks. '62' for IT)"),
name: z.string().optional().describe("Selskapsnavn eller del av navn"),
region: z.string().optional().describe("Region/kommune (f.eks. 'Bergen', 'Oslo')"),
min_employees: z.number().optional().describe("Minimum antall ansatte"),
max_employees: z.number().optional().describe("Maksimum antall ansatte"),
min_revenue: z.number().optional().describe("Minimum omsetning i NOK (millioner)"),
min_established_year: z.number().optional().describe("Minimum etableringsår (f.eks. 2020)"),
max_established_year: z.number().optional().describe("Maksimum etableringsår (f.eks. 2024)"),
min_ceo_age: z.number().optional().describe("Minimum alder for daglig leder (f.eks. 30)"),
max_ceo_age: z.number().optional().describe("Maksimum alder for daglig leder (f.eks. 60)"),
exclude_bankrupt: z.boolean().default(true).describe("Ekskluder konkursrammede selskaper"),
limit: z.number().default(50).describe("Maksimalt antall resultater")
});
export async function searchCompanies(args: unknown, db: CompanyDatabase, brreg: BrregClient) {
const params = SearchCompaniesSchema.parse(args);
console.error('Searching companies with filters:', params);
// First try database
let companies = await db.searchCompanies({
nace_code: params.industry,
name: params.name,
municipality: params.region,
min_employees: params.min_employees,
max_employees: params.max_employees,
min_established_year: params.min_established_year,
max_established_year: params.max_established_year,
min_ceo_age: params.min_ceo_age,
max_ceo_age: params.max_ceo_age,
exclude_bankrupt: params.exclude_bankrupt,
limit: params.limit
});
// If no results or few results, fetch from Brønnøysund
if (companies.length < 5) {
console.error('Fetching additional results from Brønnøysund...');
let brregResults: any[] = [];
// Try different search strategies based on parameters
if (params.name) {
// Search by company name
console.error(`Searching Brønnøysund by name: ${params.name}`);
brregResults = await brreg.searchCompanies(params.name, params.limit);
// Apply konkurs filter manually if needed (API doesn't support konkurs param with name search)
if (params.exclude_bankrupt) {
brregResults = brregResults.filter(c => !c.konkurs && !c.underAvvikling);
}
} else if (params.industry) {
// Search by NACE code (supports konkurs filtering in API)
console.error(`Searching Brønnøysund by NACE: ${params.industry}${params.exclude_bankrupt ? ' (excluding bankrupt)' : ''}`);
brregResults = await brreg.searchByNACE(params.industry, params.limit, params.exclude_bankrupt);
}
console.error(`Found ${brregResults.length} results from Brønnøysund`);
for (const company of brregResults) {
// Save to database for future queries
await db.insertOrUpdateCompany({
org_nr: company.organisasjonsnummer,
name: company.navn,
organization_form: company.organisasjonsform?.beskrivelse,
organization_form_code: company.organisasjonsform?.kode,
nace_code: company.naeringskode1?.kode,
nace_description: company.naeringskode1?.beskrivelse,
employees_count: company.antallAnsatte,
established_date: company.registreringsdatoEnhetsregisteret,
business_address: company.forretningsadresse?.adresse?.join(', '),
business_postcode: company.forretningsadresse?.postnummer,
business_city: company.forretningsadresse?.poststed,
business_municipality: company.forretningsadresse?.kommune,
business_municipality_number: company.forretningsadresse?.kommunenummer,
postal_address: company.postadresse?.adresse?.join(', '),
postal_postcode: company.postadresse?.postnummer,
postal_city: company.postadresse?.poststed,
in_mva_register: company.registrertIMvaregisteret,
in_foretaksregister: company.registrertIForetaksregisteret,
bankrupt: company.konkurs,
under_liquidation: company.underAvvikling,
under_forced_liquidation: company.underTvangsavviklingEllerTvangsopplosning,
last_updated: new Date().toISOString()
});
}
// Re-query database with all filters
companies = await db.searchCompanies({
nace_code: params.industry,
name: params.name,
municipality: params.region,
min_employees: params.min_employees,
max_employees: params.max_employees,
min_established_year: params.min_established_year,
max_established_year: params.max_established_year,
min_ceo_age: params.min_ceo_age,
max_ceo_age: params.max_ceo_age,
exclude_bankrupt: params.exclude_bankrupt,
limit: params.limit
});
// If still no results and we have filters, might need to adjust them
if (companies.length === 0 && brregResults.length > 0) {
console.error('Database filters too restrictive, returning unfiltered API results');
// Return the API results directly (already filtered by name/NACE)
companies = brregResults.map(c => ({
org_nr: c.organisasjonsnummer,
name: c.navn,
organization_form: c.organisasjonsform?.beskrivelse,
nace_code: c.naeringskode1?.kode,
nace_description: c.naeringskode1?.beskrivelse,
employees_count: c.antallAnsatte,
business_city: c.forretningsadresse?.poststed,
business_municipality: c.forretningsadresse?.kommune,
bankrupt: c.konkurs,
under_liquidation: c.underAvvikling
})).slice(0, params.limit);
}
}
if (companies.length === 0) {
return {
content: [{
type: "text" as const,
text: "Ingen selskaper funnet med disse kriteriene. Prøv å justere søket."
}]
};
}
const formattedEntries: string[] = [];
for (let idx = 0; idx < companies.length; idx++) {
const c = companies[idx];
const employees = c.employees_count ? `${c.employees_count} ansatte` : 'Ingen registrerte ansatte';
const establishedYear = c.established_date ? c.established_date.substring(0, 4) : null;
// Get CEO info if CEO age filter was used
let ceoInfo = '';
if (params.min_ceo_age || params.max_ceo_age) {
const ceo: any = await db.getCEO(c.org_nr);
if (ceo) {
const age = db.calculateAge(ceo.birth_date);
ceoInfo = `\n 👔 Daglig leder: ${ceo.name}${age ? ` (${age} år)` : ''}`;
}
}
formattedEntries.push(`${idx + 1}. **${c.name}**
📍 ${c.business_city || 'Ukjent'}, ${c.business_municipality || ''}
🏢 ${c.organization_form || 'Ukjent'}
👥 ${employees}
🏷️ NACE: ${c.nace_code || 'Ukjent'} - ${c.nace_description || ''}
📋 Org.nr: ${c.org_nr}${establishedYear ? `\n 📅 Etablert: ${establishedYear}` : ''}${ceoInfo}
${c.bankrupt ? '⚠️ KONKURS' : ''}${c.under_liquidation ? '⚠️ AVVIKLING' : ''}`);
}
const formatted = formattedEntries.join('\n\n');
return {
content: [{
type: "text" as const,
text: `Fant ${companies.length} selskaper:\n\n${formatted}\n\n💡 Bruk 'analyze_growth' eller 'analyze_ownership' for dybdeanalyse.`
}]
};
}