import 'dart:async';
import 'package:pocketbase/pocketbase.dart';
import '../../../core/api/pocketbase_client.dart';
import '../../../core/services/finance_service.dart';
import '../../../core/services/job_history_service.dart';
import '../../../models/job.dart';

const _listExpand = 'clinic_tenant_id,lab_tenant_id,patient_id';
const _detailExpand = 'clinic_tenant_id,lab_tenant_id,patient_id,prosthetic_id';

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

  PocketBase get _pb => PocketBaseClient.instance.pb;

  Future<List<Job>> listOutbound(
    String clinicTenantId, {
    List<String>? statuses,
    String? location,
    String? filterExtra,
    int page = 1,
    int limit = 30,
  }) async {
    final filterParts = ['clinic_tenant_id = "$clinicTenantId"'];
    if (statuses != null && statuses.isNotEmpty) {
      final statusFilter = statuses.map((s) => 'status = "$s"').join(' || ');
      filterParts.add('($statusFilter)');
    }
    if (location != null) {
      filterParts.add('location = "$location"');
    }
    if (filterExtra != null) {
      filterParts.add('($filterExtra)');
    }

    final result = await _pb.collection('jobs').getList(
          page: page,
          perPage: limit,
          filter: filterParts.join(' && '),
          expand: _listExpand,
          sort: '-created',
        );
    return (result.items.map((r) => Job.fromJson(r.toJson())).toList()
      ..sort((a, b) => b.dateCreated.compareTo(a.dateCreated)));
  }

  Future<Job> getJob(String jobId) async {
    final record =
        await _pb.collection('jobs').getOne(jobId, expand: _detailExpand);
    return Job.fromJson(record.toJson());
  }

  Future<Job> createJob({
    required String clinicTenantId,
    required String labTenantId,
    required String clinicName,
    required String labName,
    required String patientCode,
    String? prostheticId,
    required ProstheticType prostheticType,
    required List<String> teeth,
    String? patientId,
    String? color,
    String? description,
    String? dueDate,
    double? price,
    String? currency,
    JobWorkflowType? workflowType,
    bool provaRequired = true,
    List<String> workflowSteps = const [],
  }) async {
    final record = await _pb.collection('jobs').create(body: {
      'clinic_tenant_id': clinicTenantId,
      'lab_tenant_id': labTenantId,
      'patient_code': patientCode,
      if (patientId != null) 'patient_id': patientId,
      if (prostheticId != null && prostheticId.isNotEmpty)
        'prosthetic_id': prostheticId,
      'prosthetic_type': prostheticType.value,
      'member_count': teeth.length,
      'teeth': teeth,
      if (color != null) 'color': color,
      if (description != null) 'description': description,
      if (dueDate != null) 'due_date': dueDate,
      if (price != null) 'price': price,
      if (currency != null && currency.isNotEmpty) 'currency': currency,
      if (workflowType != null) 'workflow_type': workflowType.value,
      if (workflowSteps.isNotEmpty) 'workflow_steps': workflowSteps,
      'status': 'pending',
      'location': 'at_clinic',
      'prova_required': provaRequired,
    });
    final job = Job.fromJson(record.toJson());
    if (price != null && price > 0) {
      try {
        await FinanceService.instance.ensureEntriesForJob(
          jobId: job.id,
          clinicTenantId: clinicTenantId,
          labTenantId: labTenantId,
          clinicName: clinicName,
          labName: labName,
          amount: price,
          currency: currency ?? 'TRY',
        );
      } catch (_) {
        await _pb.collection('jobs').delete(job.id);
        rethrow;
      }
    }
    return job;
  }

  Future<Job> approveAtClinic(String jobId, Job job, {String? note}) async {
    final nextStep = job.nextStep;
    if (nextStep == null) throw Exception('Bu aşamadan ileri gidilemez.');

    final record = await _pb.collection('jobs').update(jobId, body: {
      'current_step': nextStep.value,
      'location': 'at_lab',
    });
    final updated = Job.fromJson(record.toJson());
    unawaited(JobHistoryService.instance.append(
      jobId: jobId,
      clinicTenantId: job.clinicTenantId,
      labTenantId: job.labTenantId,
      action: JobHistoryAction.approved,
      step: job.currentStep,
      note: note,
    ));
    return updated;
  }

  Future<Job> requestRevision(String jobId, Job job,
      {required String note}) async {
    final record = await _pb.collection('jobs').update(jobId, body: {
      'location': 'at_lab',
    });
    final updated = Job.fromJson(record.toJson());
    await JobHistoryService.instance.append(
      jobId: jobId,
      clinicTenantId: job.clinicTenantId,
      labTenantId: job.labTenantId,
      action: JobHistoryAction.revisionRequested,
      step: job.currentStep,
      note: note,
    );
    return updated;
  }

  Future<Job> markDelivered(String jobId, Job job, {String? note}) async {
    final record = await _pb.collection('jobs').update(jobId, body: {
      'status': 'delivered',
    });
    unawaited(JobHistoryService.instance.append(
      jobId: jobId,
      clinicTenantId: job.clinicTenantId,
      labTenantId: job.labTenantId,
      action: JobHistoryAction.delivered,
      note: note,
    ));
    return Job.fromJson(record.toJson());
  }

  Future<Job> cancelJob(String jobId, Job job) async {
    final record = await _pb.collection('jobs').update(jobId, body: {
      'status': 'cancelled',
    });
    await FinanceService.instance.deletePendingEntriesForJob(jobId);
    unawaited(JobHistoryService.instance.append(
      jobId: jobId,
      clinicTenantId: job.clinicTenantId,
      labTenantId: job.labTenantId,
      action: JobHistoryAction.cancelled,
    ));
    return Job.fromJson(record.toJson());
  }

  Future<List<Map<String, dynamic>>> listApprovedLabs(
      String clinicTenantId) async {
    final result = await _pb.collection('connections').getList(
          filter: 'clinic_tenant_id = "$clinicTenantId" && status = "approved"',
          expand: 'lab_tenant_id',
          perPage: 100,
        );
    return result.items.map((r) {
      final expand = r.toJson()['expand'] as Map<String, dynamic>?;
      return expand?['lab_tenant_id'] as Map<String, dynamic>? ??
          {'id': r.data['lab_tenant_id']};
    }).toList();
  }

  Future<List<Job>> listJobsByPatient(String patientId,
      {int limit = 50}) async {
    final result = await _pb.collection('jobs').getList(
          filter: 'patient_id = "$patientId"',
          perPage: limit,
          expand: _listExpand,
          sort: '-created',
        );
    return (result.items.map((r) => Job.fromJson(r.toJson())).toList()
      ..sort((a, b) => b.dateCreated.compareTo(a.dateCreated)));
  }

  Future<int> countDelivered(String clinicTenantId,
      {DateTime? from, DateTime? to}) async {
    final parts = [
      'clinic_tenant_id = "$clinicTenantId"',
      'status = "delivered"'
    ];
    if (from != null) parts.add('updated >= "${_date(from)}"');
    if (to != null) parts.add('updated < "${_date(to)}"');
    final r = await _pb
        .collection('jobs')
        .getList(perPage: 1, filter: parts.join(' && '));
    return r.totalItems;
  }

  static String _date(DateTime d) => d.toIso8601String().split('T').first;
}
