import 'package:pocketbase/pocketbase.dart';
import '../../core/api/pocketbase_client.dart';
import '../../models/tenant.dart';

// ── Value objects ─────────────────────────────────────────────────────────────

const _monthLabels = ['Oca','Şub','Mar','Nis','May','Haz','Tem','Ağu','Eyl','Eki','Kas','Ara'];

class MonthlyCount {
  const MonthlyCount({required this.year, required this.month, required this.count});
  final int year, month, count;
  String get label => _monthLabels[month - 1];
}

class MonthlyAmount {
  const MonthlyAmount({required this.year, required this.month, required this.amount});
  final int year, month;
  final double amount;
  String get label => _monthLabels[month - 1];
}

class CounterpartStat {
  const CounterpartStat({required this.name, required this.jobCount, required this.pendingRevenue, required this.paidRevenue});
  final String name;
  final int jobCount;
  final double pendingRevenue, paidRevenue;
  double get totalRevenue => pendingRevenue + paidRevenue;
}

class ActivityItem {
  const ActivityItem({required this.jobId, this.patientCode, required this.action, required this.createdAt, this.note});
  final String jobId, action;
  final String? patientCode, note;
  final DateTime createdAt;

  String get actionLabel => switch (action) {
    'accepted'           => 'İş kabul edildi',
    'handed_to_clinic'   => 'Provaya gönderildi',
    'approved'           => 'Onaylandı',
    'revision_requested' => 'Revizyon istendi',
    'delivered'          => 'Teslim edildi',
    'cancelled'          => 'İptal edildi',
    _                    => action,
  };

  bool get isNegative => action == 'revision_requested' || action == 'cancelled';
  bool get isPositive => action == 'delivered' || action == 'approved' || action == 'accepted';
}

// ── Aggregated metrics ────────────────────────────────────────────────────────

class ReportMetrics {
  const ReportMetrics({
    required this.activeJobs,
    required this.completedThisMonth,
    required this.overdueJobs,
    required this.revisionRate,
    required this.avgCompletionDays,
    required this.totalRevenue,
    required this.pendingRevenue,
    required this.currency,
    required this.jobsByStatus,
    required this.monthlyCounts,
    required this.monthlyRevenue,
    required this.byProstheticType,
    required this.counterpartStats,
    required this.recentActivity,
  });

  final int activeJobs;
  final int completedThisMonth;
  final int overdueJobs;
  final double revisionRate; // 0-100
  final double avgCompletionDays;
  final double totalRevenue;
  final double pendingRevenue;
  final String currency;

  final Map<String, int> jobsByStatus;
  final List<MonthlyCount> monthlyCounts;
  final List<MonthlyAmount> monthlyRevenue;
  final Map<String, int> byProstheticType;
  final List<CounterpartStat> counterpartStats;
  final List<ActivityItem> recentActivity;
}

// ── Repository ────────────────────────────────────────────────────────────────

class ReportsRepository {
  ReportsRepository._();
  static final instance = ReportsRepository._();

  PocketBase get _pb => PocketBaseClient.instance.pb;

  Future<ReportMetrics> load(String tenantId, TenantKind kind) async {
    final jobFilter = kind == TenantKind.lab
        ? 'lab_tenant_id = "$tenantId"'
        : 'clinic_tenant_id = "$tenantId"';
    final historyFilter = kind == TenantKind.lab
        ? 'lab_tenant_id = "$tenantId"'
        : 'clinic_tenant_id = "$tenantId"';

    final results = await Future.wait([
      _pb.collection('jobs').getList(
        filter: jobFilter,
        perPage: 500,
        expand: kind == TenantKind.lab ? 'clinic_tenant_id' : 'lab_tenant_id',
        fields: 'id,status,prosthetic_type,clinic_tenant_id,lab_tenant_id,created,updated,due_date,price,currency,expand',
      ).catchError((_) => ResultList<RecordModel>()),
      _pb.collection('finance_entries').getList(
        filter: 'tenant_id = "$tenantId"',
        perPage: 300,
        fields: 'id,amount,currency,status,created,counterparty_name',
      ).catchError((_) => ResultList<RecordModel>()),
      _pb.collection('job_status_history').getList(
        filter: historyFilter,
        perPage: 100,
        expand: 'job_id',
        fields: 'id,action_type,created,note,job_id,expand',
      ).catchError((_) => ResultList<RecordModel>()),
    ]);

    final jobRecords    = (results[0] as ResultList<RecordModel>).items;
    final financeRecords = (results[1] as ResultList<RecordModel>).items;
    final historyRecords = (results[2] as ResultList<RecordModel>).items;

    return _aggregate(tenantId, kind, jobRecords, financeRecords, historyRecords);
  }

  ReportMetrics _aggregate(
    String tenantId,
    TenantKind kind,
    List<RecordModel> jobRecords,
    List<RecordModel> financeRecords,
    List<RecordModel> historyRecords,
  ) {
    final now = DateTime.now();
    final thisMonthStart = DateTime(now.year, now.month, 1);

    // ── Parse jobs ────────────────────────────────────────────────────────────
    String _s(Map<String, dynamic> j, String k) {
      final v = j[k];
      if (v == null || v == '') return '';
      return v.toString();
    }

    final jobs = jobRecords.map((r) {
      final j = r.toJson();
      final exp = j['expand'] as Map<String, dynamic>?;
      final cpKey = kind == TenantKind.lab ? 'clinic_tenant_id' : 'lab_tenant_id';
      final cpExp = exp?[cpKey] as Map<String, dynamic>?;
      return _RawJob(
        id: _s(j, 'id'),
        status: _s(j, 'status'),
        prostheticType: _s(j, 'prosthetic_type'),
        clinicTenantId: _s(j, 'clinic_tenant_id'),
        labTenantId: _s(j, 'lab_tenant_id'),
        created: _parseDate(j['created']),
        updated: _parseDate(j['updated']),
        dueDate: j['due_date'] != null && j['due_date'] != '' ? _parseDate(j['due_date']) : null,
        currency: _s(j, 'currency').isNotEmpty ? _s(j, 'currency') : 'TRY',
        counterpartName: cpExp?['company_name'] as String? ?? '',
      );
    }).toList();

    // ── Parse finance ─────────────────────────────────────────────────────────
    String topCurrency = 'TRY';
    final financeList = financeRecords.map((r) {
      final j = r.toJson();
      final cur = (j['currency'] as String?) ?? 'TRY';
      if (cur.isNotEmpty) topCurrency = cur;
      return _RawFinance(
        status: (j['status'] as String?) ?? '',
        amount: (j['amount'] as num?)?.toDouble() ?? 0,
        created: _parseDate(j['created']),
        counterpartyName: j['counterparty_name'] as String?,
      );
    }).toList();

    // ── Parse history ─────────────────────────────────────────────────────────
    final activity = historyRecords.map((r) {
      final j = r.toJson();
      final exp = j['expand'] as Map<String, dynamic>?;
      final jobExp = exp?['job_id'] as Map<String, dynamic>?;
      return ActivityItem(
        jobId: (j['job_id'] as String?) ?? '',
        patientCode: jobExp?['patient_code'] as String?,
        action: (j['action_type'] as String?) ?? '',
        createdAt: _parseDate(j['created']),
        note: j['note'] as String?,
      );
    }).toList()
      ..sort((a, b) => b.createdAt.compareTo(a.createdAt));

    // ── KPI metrics ───────────────────────────────────────────────────────────
    final activeJobs = jobs.where((j) => j.status == 'in_progress' || j.status == 'pending').length;
    final completedThisMonth = jobs.where((j) => j.status == 'delivered' && j.updated.isAfter(thisMonthStart)).length;
    final overdueJobs = jobs.where((j) =>
        j.dueDate != null &&
        j.dueDate!.isBefore(now) &&
        (j.status == 'in_progress' || j.status == 'pending')).length;

    final revisions = activity.where((a) => a.action == 'revision_requested').length;
    final revisionRate = activity.isNotEmpty ? revisions / activity.length * 100 : 0.0;

    final deliveredJobs = jobs.where((j) => j.status == 'delivered').toList();
    final avgCompletionDays = deliveredJobs.isNotEmpty
        ? deliveredJobs
                .fold<int>(0, (s, j) => s + j.updated.difference(j.created).inDays) /
            deliveredJobs.length
        : 0.0;

    // ── Finance totals ────────────────────────────────────────────────────────
    final totalRevenue  = financeList.where((f) => f.status == 'paid').fold<double>(0, (s, f) => s + f.amount);
    final pendingRevenue = financeList.where((f) => f.status == 'pending').fold<double>(0, (s, f) => s + f.amount);

    // ── Job status distribution ───────────────────────────────────────────────
    final Map<String, int> jobsByStatus = {};
    for (final j in jobs) {
      jobsByStatus[j.status] = (jobsByStatus[j.status] ?? 0) + 1;
    }

    // ── Monthly job counts (last 6 months) ────────────────────────────────────
    final monthKeys = List.generate(6, (i) {
      final d = DateTime(now.year, now.month - 5 + i, 1);
      return '${d.year}-${d.month}';
    });
    final monthMap = {for (final k in monthKeys) k: 0};
    for (final j in jobs) {
      final key = '${j.created.year}-${j.created.month}';
      if (monthMap.containsKey(key)) monthMap[key] = monthMap[key]! + 1;
    }
    final monthlyCounts = monthKeys.map((k) {
      final parts = k.split('-');
      return MonthlyCount(year: int.parse(parts[0]), month: int.parse(parts[1]), count: monthMap[k]!);
    }).toList();

    // ── Monthly revenue (last 6 months) ──────────────────────────────────────
    final revMap = {for (final k in monthKeys) k: 0.0};
    for (final f in financeList) {
      if (f.status == 'paid') {
        final key = '${f.created.year}-${f.created.month}';
        if (revMap.containsKey(key)) revMap[key] = revMap[key]! + f.amount;
      }
    }
    final monthlyRevenue = monthKeys.map((k) {
      final parts = k.split('-');
      return MonthlyAmount(year: int.parse(parts[0]), month: int.parse(parts[1]), amount: revMap[k]!);
    }).toList();

    // ── By prosthetic type ────────────────────────────────────────────────────
    final Map<String, int> byType = {};
    for (final j in jobs) {
      if (j.prostheticType.isNotEmpty) {
        byType[j.prostheticType] = (byType[j.prostheticType] ?? 0) + 1;
      }
    }

    // ── By counterpart ────────────────────────────────────────────────────────
    final Map<String, int> cpCount = {};
    final Map<String, double> cpPending = {}, cpPaid = {};
    for (final j in jobs) {
      final name = j.counterpartName.isNotEmpty ? j.counterpartName : '—';
      cpCount[name] = (cpCount[name] ?? 0) + 1;
    }
    for (final f in financeList) {
      final name = f.counterpartyName ?? '—';
      if (f.status == 'pending') cpPending[name] = (cpPending[name] ?? 0) + f.amount;
      if (f.status == 'paid') cpPaid[name] = (cpPaid[name] ?? 0) + f.amount;
    }
    final counterparts = cpCount.entries
        .map((e) => CounterpartStat(
              name: e.key,
              jobCount: e.value,
              pendingRevenue: cpPending[e.key] ?? 0,
              paidRevenue: cpPaid[e.key] ?? 0,
            ))
        .toList()
      ..sort((a, b) => b.jobCount.compareTo(a.jobCount));

    return ReportMetrics(
      activeJobs: activeJobs,
      completedThisMonth: completedThisMonth,
      overdueJobs: overdueJobs,
      revisionRate: revisionRate,
      avgCompletionDays: avgCompletionDays,
      totalRevenue: totalRevenue,
      pendingRevenue: pendingRevenue,
      currency: topCurrency,
      jobsByStatus: jobsByStatus,
      monthlyCounts: monthlyCounts,
      monthlyRevenue: monthlyRevenue,
      byProstheticType: byType,
      counterpartStats: counterparts.take(5).toList(),
      recentActivity: activity.take(30).toList(),
    );
  }

  static DateTime _parseDate(dynamic v) {
    if (v == null || v == '') return DateTime(2000);
    return DateTime.tryParse(v.toString()) ?? DateTime(2000);
  }
}

// ── Internal raw models ───────────────────────────────────────────────────────

class _RawJob {
  const _RawJob({
    required this.id, required this.status, required this.prostheticType,
    required this.clinicTenantId, required this.labTenantId,
    required this.created, required this.updated,
    required this.currency, required this.counterpartName, this.dueDate,
  });
  final String id, status, prostheticType, clinicTenantId, labTenantId, currency, counterpartName;
  final DateTime created, updated;
  final DateTime? dueDate;
}

class _RawFinance {
  const _RawFinance({required this.status, required this.amount, required this.created, this.counterpartyName});
  final String status;
  final double amount;
  final DateTime created;
  final String? counterpartyName;
}
