import 'package:equatable/equatable.dart'; import 'ticker_model.dart'; import 'company_officer_model.dart'; import 'financial_statement_model.dart'; import 'forward_estimate_model.dart'; export 'ticker_model.dart'; export 'company_officer_model.dart'; export 'financial_statement_model.dart'; export 'forward_estimate_model.dart'; class FundamentalDataModel extends Equatable { final String isin; final String primaryTicker; final String ticker; final String companyName; final String? exchange; final String? tradingCurrency; final String? businessSummary; final String? sector; final String? industry; final String? country; final int? employees; final double currentPrice; final double dayChangeAbsolute; final double dayChangePercent; final double? fiftyTwoWeekHigh; final double? fiftyTwoWeekLow; final double? marketCapitalization; final double? enterpriseValue; final double? peRatioTrailing; final double? peRatioForward; final double? pegRatio; final double? pbRatio; final double? psRatio; final double? evToEbitda; final double? evToRevenue; final double? totalRevenue; final double? revenueGrowthYoY; final double? grossProfit; final double? ebitda; final double? dilutedEps; final double? totalCash; final double? totalDebt; final double? operatingCashFlow; final double? freeCashFlow; final double? grossMargin; final double? operatingMargin; final double? netProfitMargin; final double? returnOnEquity; final double? returnOnAssets; final double? returnOnInvestedCapital; final double? debtToEquity; final double? currentRatio; final double? quickRatio; final double? interestCoverage; final double? dividendYield; final double? payoutRatio; final String? exDividendDate; final String? nextEarningsDate; final double? percentHeldByInstitutions; final double? percentHeldByInsiders; final double? shortRatio; final double? shortPercentOfFloat; final String? consensusRating; final double? priceTargetLow; final double? priceTargetHigh; final double? priceTargetMedian; final double? priceTargetMean; final List executives; final List financialStatements; final List estimates; final List availableTickers; const FundamentalDataModel({ required this.isin, required this.primaryTicker, required this.ticker, required this.companyName, this.exchange, this.tradingCurrency, this.businessSummary, this.sector, this.industry, this.country, this.employees, required this.currentPrice, required this.dayChangeAbsolute, required this.dayChangePercent, this.fiftyTwoWeekHigh, this.fiftyTwoWeekLow, this.marketCapitalization, this.enterpriseValue, this.peRatioTrailing, this.peRatioForward, this.pegRatio, this.pbRatio, this.psRatio, this.evToEbitda, this.evToRevenue, this.totalRevenue, this.revenueGrowthYoY, this.grossProfit, this.ebitda, this.dilutedEps, this.totalCash, this.totalDebt, this.operatingCashFlow, this.freeCashFlow, this.grossMargin, this.operatingMargin, this.netProfitMargin, this.returnOnEquity, this.returnOnAssets, this.returnOnInvestedCapital, this.debtToEquity, this.currentRatio, this.quickRatio, this.interestCoverage, this.dividendYield, this.payoutRatio, this.exDividendDate, this.nextEarningsDate, this.percentHeldByInstitutions, this.percentHeldByInsiders, this.shortRatio, this.shortPercentOfFloat, this.consensusRating, this.priceTargetLow, this.priceTargetHigh, this.priceTargetMedian, this.priceTargetMean, required this.executives, required this.financialStatements, required this.estimates, this.availableTickers = const [], }); factory FundamentalDataModel.fromJson(Map json) { double? parseNullableDouble(dynamic val) { if (val == null) return null; if (val is num) return val.toDouble(); return double.tryParse(val.toString()); } final assetMap = json['asset'] is Map ? json['asset'] as Map : null; final fundMap = json['fundamentals'] is Map ? json['fundamentals'] as Map : null; String extractTickerStr(dynamic val) { if (val == null) return ''; if (val is Map) { return val['ticker']?.toString() ?? ''; } return val.toString(); } String? extractExchangeStr(dynamic val) { if (val == null) return null; if (val is Map) { return val['exchange']?.toString(); } return null; } final isinVal = assetMap?['isin']?.toString() ?? json['isin']?.toString() ?? ''; final primaryTickerVal = extractTickerStr(assetMap?['primaryTicker'] ?? json['primaryTicker']); final tickerVal = extractTickerStr(fundMap?['ticker'] ?? json['ticker']).isNotEmpty ? extractTickerStr(fundMap?['ticker'] ?? json['ticker']) : primaryTickerVal; final companyNameVal = assetMap?['name']?.toString() ?? json['companyName']?.toString() ?? tickerVal; final businessSummaryVal = assetMap?['description']?.toString() ?? json['businessSummary']?.toString(); final exchangeVal = extractExchangeStr(fundMap?['ticker']) ?? extractExchangeStr(assetMap?['primaryTicker']) ?? json['exchange']?.toString(); final rawTickers = assetMap?['availableTickers'] ?? json['availableTickers']; List availableTickersList = []; if (rawTickers is List) { availableTickersList = rawTickers .whereType>() .map((t) => TickerModel.fromJson(t)) .toList(); } final totalRev = parseNullableDouble(fundMap?['totalRevenue'] ?? json['totalRevenue']); final grossProf = parseNullableDouble(fundMap?['grossProfit'] ?? json['grossProfit']); double? grossMarginVal = parseNullableDouble(fundMap?['grossMargin'] ?? json['grossMargin']); if (grossMarginVal == null && grossProf != null) { if (grossProf <= 1.0 && grossProf >= 0.0) { grossMarginVal = grossProf; } else if (totalRev != null && totalRev > 0) { grossMarginVal = grossProf / totalRev; } } final evVal = parseNullableDouble(fundMap?['enterpriseValue'] ?? json['enterpriseValue']); double? evToRevVal = parseNullableDouble(fundMap?['evToRevenue'] ?? fundMap?['enterpriseValueToRevenue'] ?? json['evToRevenue']); if (evToRevVal == null && evVal != null && totalRev != null && totalRev > 0) { evToRevVal = evVal / totalRev; } return FundamentalDataModel( isin: isinVal, primaryTicker: primaryTickerVal, ticker: tickerVal, companyName: companyNameVal, exchange: exchangeVal, tradingCurrency: fundMap?['currency']?.toString() ?? json['tradingCurrency']?.toString(), businessSummary: businessSummaryVal, sector: assetMap?['sector']?.toString() ?? json['sector']?.toString(), industry: assetMap?['industry']?.toString() ?? json['industry']?.toString(), country: assetMap?['country']?.toString() ?? json['country']?.toString(), employees: (assetMap?['employees'] ?? json['employees']) is int ? (assetMap?['employees'] ?? json['employees']) as int : int.tryParse((assetMap?['employees'] ?? json['employees'])?.toString() ?? ''), currentPrice: parseNullableDouble(fundMap?['currentPrice'] ?? json['currentPrice']) ?? 0.0, dayChangeAbsolute: parseNullableDouble(fundMap?['dayChangeAbsolute'] ?? json['dayChangeAbsolute']) ?? 0.0, dayChangePercent: parseNullableDouble(fundMap?['dayChangePercent'] ?? json['dayChangePercent']) ?? 0.0, fiftyTwoWeekHigh: parseNullableDouble(fundMap?['fiftyTwoWeekHigh'] ?? json['fiftyTwoWeekHigh']), fiftyTwoWeekLow: parseNullableDouble(fundMap?['fiftyTwoWeekLow'] ?? json['fiftyTwoWeekLow']), marketCapitalization: parseNullableDouble(fundMap?['marketCap'] ?? fundMap?['marketCapitalization'] ?? json['marketCapitalization']), enterpriseValue: evVal, peRatioTrailing: parseNullableDouble(fundMap?['trailingPE'] ?? fundMap?['peRatioTrailing'] ?? json['peRatioTrailing']), peRatioForward: parseNullableDouble(fundMap?['forwardPE'] ?? fundMap?['peRatioForward'] ?? json['peRatioForward']), pegRatio: parseNullableDouble(fundMap?['pegRatio'] ?? json['pegRatio']), pbRatio: parseNullableDouble(fundMap?['priceToBook'] ?? fundMap?['pbRatio'] ?? json['pbRatio']), psRatio: parseNullableDouble(fundMap?['priceToSalesTrailing12Months'] ?? fundMap?['psRatio'] ?? json['psRatio']), evToEbitda: parseNullableDouble(fundMap?['enterpriseToEbitda'] ?? fundMap?['evToEbitda'] ?? json['evToEbitda']), evToRevenue: evToRevVal, totalRevenue: totalRev, revenueGrowthYoY: parseNullableDouble(fundMap?['revenueGrowth'] ?? fundMap?['revenueGrowthYoY'] ?? json['revenueGrowthYoY']), grossProfit: grossProf, ebitda: parseNullableDouble(fundMap?['ebitda'] ?? json['ebitda']), dilutedEps: parseNullableDouble(fundMap?['trailingEps'] ?? fundMap?['dilutedEps'] ?? json['dilutedEps']), totalCash: parseNullableDouble(fundMap?['totalCash'] ?? json['totalCash']), totalDebt: parseNullableDouble(fundMap?['totalDebt'] ?? json['totalDebt']), operatingCashFlow: parseNullableDouble(fundMap?['operatingCashflow'] ?? fundMap?['operatingCashFlow'] ?? json['operatingCashFlow']), freeCashFlow: parseNullableDouble(fundMap?['freeCashflow'] ?? fundMap?['freeCashFlow'] ?? json['freeCashFlow']), grossMargin: grossMarginVal, operatingMargin: parseNullableDouble(fundMap?['operatingMargins'] ?? fundMap?['operatingMargin'] ?? json['operatingMargin']), netProfitMargin: parseNullableDouble(fundMap?['profitMargins'] ?? fundMap?['netProfitMargin'] ?? json['netProfitMargin']), returnOnEquity: parseNullableDouble(fundMap?['returnOnEquity'] ?? json['returnOnEquity']), returnOnAssets: parseNullableDouble(fundMap?['returnOnAssets'] ?? json['returnOnAssets']), returnOnInvestedCapital: parseNullableDouble(fundMap?['returnOnInvestedCapital'] ?? json['returnOnInvestedCapital']), debtToEquity: parseNullableDouble(fundMap?['debtToEquity'] ?? json['debtToEquity']), currentRatio: parseNullableDouble(fundMap?['currentRatio'] ?? json['currentRatio']), quickRatio: parseNullableDouble(fundMap?['quickRatio'] ?? json['quickRatio']), interestCoverage: parseNullableDouble(fundMap?['interestCoverage'] ?? json['interestCoverage']), dividendYield: parseNullableDouble(fundMap?['dividendYield'] ?? json['dividendYield']), payoutRatio: parseNullableDouble(fundMap?['payoutRatio'] ?? json['payoutRatio']), exDividendDate: fundMap?['exDividendDate']?.toString() ?? json['exDividendDate']?.toString(), nextEarningsDate: fundMap?['nextEarningsDate']?.toString() ?? json['nextEarningsDate']?.toString(), percentHeldByInstitutions: parseNullableDouble(fundMap?['percentHeldByInstitutions'] ?? json['percentHeldByInstitutions']), percentHeldByInsiders: parseNullableDouble(fundMap?['percentHeldByInsiders'] ?? json['percentHeldByInsiders']), shortRatio: parseNullableDouble(fundMap?['shortRatio'] ?? json['shortRatio']), shortPercentOfFloat: parseNullableDouble(fundMap?['shortPercentOfFloat'] ?? json['shortPercentOfFloat']), consensusRating: fundMap?['consensusRating']?.toString() ?? json['consensusRating']?.toString(), priceTargetLow: parseNullableDouble(fundMap?['priceTargetLow'] ?? json['priceTargetLow']), priceTargetHigh: parseNullableDouble(fundMap?['priceTargetHigh'] ?? json['priceTargetHigh']), priceTargetMedian: parseNullableDouble(fundMap?['priceTargetMedian'] ?? json['priceTargetMedian']), priceTargetMean: parseNullableDouble(fundMap?['priceTargetMean'] ?? json['priceTargetMean']), executives: (json['executives'] as List?) ?.whereType>() .map((e) => CompanyExecutiveModel.fromJson(e)) .toList() ?? [], financialStatements: (json['financialStatements'] as List?) ?.whereType>() .map((e) => FinancialStatementModel.fromJson(e)) .toList() ?? [], estimates: (json['estimates'] as List?) ?.whereType>() .map((e) => ForwardEstimateModel.fromJson(e)) .toList() ?? [], availableTickers: availableTickersList, ); } @override List get props => [ isin, primaryTicker, ticker, companyName, exchange, tradingCurrency, businessSummary, sector, industry, country, employees, currentPrice, dayChangeAbsolute, dayChangePercent, fiftyTwoWeekHigh, fiftyTwoWeekLow, marketCapitalization, enterpriseValue, peRatioTrailing, peRatioForward, pegRatio, pbRatio, psRatio, evToEbitda, evToRevenue, grossMargin, operatingMargin, netProfitMargin, returnOnEquity, returnOnAssets, returnOnInvestedCapital, debtToEquity, currentRatio, quickRatio, dividendYield, payoutRatio, exDividendDate, nextEarningsDate, percentHeldByInstitutions, percentHeldByInsiders, shortRatio, shortPercentOfFloat, consensusRating, priceTargetLow, priceTargetHigh, priceTargetMedian, priceTargetMean, executives, financialStatements, estimates, availableTickers, ]; }