<?php

namespace Modules\Sale\Services;

use App\Models\ActivityLogModel;
use App\Models\SalesCommissionModel;
use App\Models\SalesRepresentativeModel;
use App\Models\SalesTargetModel;
use App\Models\SalesTerritoryModel;

class SalesTargetCommissionService
{
    protected SalesTargetModel $targets;
    protected SalesCommissionModel $commissions;
    protected SalesRepresentativeModel $reps;
    protected SalesTerritoryModel $territories;
    protected ActivityLogModel $activity;

    public function __construct()
    {
        $this->targets     = new SalesTargetModel();
        $this->commissions = new SalesCommissionModel();
        $this->reps        = new SalesRepresentativeModel();
        $this->territories = new SalesTerritoryModel();
        $this->activity    = new ActivityLogModel();
    }

    // --- Targets ---

    public function createTarget(array $input, ?int $actingUserId): array
    {
        $repId = (int) ($input['sales_rep_id'] ?? 0);
        if (! $this->reps->find($repId)) {
            return ['success' => false, 'errors' => ['sales_rep_id' => 'Sales representative not found.']];
        }

        $data = $this->mapTargetInput($input);
        $data['created_by'] = $actingUserId;
        $data['updated_by'] = $actingUserId;

        if (! $this->targets->insert($data, true)) {
            return ['success' => false, 'errors' => $this->targets->errors()];
        }

        $id = (int) $this->targets->getInsertID();
        $this->activity->log('sales_targets', 'created', $actingUserId, "Created sales target #{$id}", (string) $id);

        return ['success' => true, 'id' => $id];
    }

    public function updateTarget(int $id, array $input, ?int $actingUserId): array
    {
        if (! $this->targets->find($id)) {
            return ['success' => false, 'errors' => ['id' => 'Target not found.']];
        }

        $repId = (int) ($input['sales_rep_id'] ?? 0);
        if (! $this->reps->find($repId)) {
            return ['success' => false, 'errors' => ['sales_rep_id' => 'Sales representative not found.']];
        }

        $data = $this->mapTargetInput($input);
        $data['updated_by'] = $actingUserId;

        if (! $this->targets->update($id, $data)) {
            return ['success' => false, 'errors' => $this->targets->errors()];
        }

        $this->activity->log('sales_targets', 'updated', $actingUserId, "Updated sales target #{$id}", (string) $id);

        return ['success' => true];
    }

    public function deleteTarget(int $id, ?int $actingUserId): array
    {
        if (! $this->targets->find($id)) {
            return ['success' => false, 'error' => 'Target not found.'];
        }
        $this->targets->delete($id);
        $this->activity->log('sales_targets', 'deleted', $actingUserId, "Deleted sales target #{$id}", (string) $id);

        return ['success' => true];
    }

    // --- Commissions ---

    public function createCommission(array $input, ?int $actingUserId): array
    {
        $repId = (int) ($input['sales_rep_id'] ?? 0);
        if (! $this->reps->find($repId)) {
            return ['success' => false, 'errors' => ['sales_rep_id' => 'Sales representative not found.']];
        }

        $data = $this->mapCommissionInput($input);
        $data['status']     = 'draft';
        $data['created_by'] = $actingUserId;
        $data['updated_by'] = $actingUserId;

        if (! $this->commissions->insert($data, true)) {
            return ['success' => false, 'errors' => $this->commissions->errors()];
        }

        $id = (int) $this->commissions->getInsertID();
        $this->activity->log('sales_commissions', 'created', $actingUserId, "Created commission #{$id}", (string) $id);

        return ['success' => true, 'id' => $id];
    }

    public function updateCommission(int $id, array $input, ?int $actingUserId): array
    {
        $row = $this->commissions->find($id);
        if (! $row) {
            return ['success' => false, 'errors' => ['id' => 'Commission not found.']];
        }
        if ($row['status'] !== 'draft') {
            return ['success' => false, 'errors' => ['status' => 'Only draft commissions can be edited.']];
        }

        $repId = (int) ($input['sales_rep_id'] ?? 0);
        if (! $this->reps->find($repId)) {
            return ['success' => false, 'errors' => ['sales_rep_id' => 'Sales representative not found.']];
        }

        $data = $this->mapCommissionInput($input);
        $data['updated_by'] = $actingUserId;

        if (! $this->commissions->update($id, $data)) {
            return ['success' => false, 'errors' => $this->commissions->errors()];
        }

        $this->activity->log('sales_commissions', 'updated', $actingUserId, "Updated commission #{$id}", (string) $id);

        return ['success' => true];
    }

    public function approveCommission(int $id, ?int $actingUserId): array
    {
        $row = $this->commissions->find($id);
        if (! $row) {
            return ['success' => false, 'error' => 'Commission not found.'];
        }
        if ($row['status'] !== 'draft') {
            return ['success' => false, 'error' => 'Only draft commissions can be approved.'];
        }

        $this->commissions->update($id, [
            'status'      => 'approved',
            'approved_at' => date('Y-m-d H:i:s'),
            'updated_by'  => $actingUserId,
        ]);
        $this->activity->log('sales_commissions', 'approved', $actingUserId, "Approved commission #{$id}", (string) $id);

        return ['success' => true];
    }

    public function markCommissionPaid(int $id, ?int $actingUserId): array
    {
        $row = $this->commissions->find($id);
        if (! $row) {
            return ['success' => false, 'error' => 'Commission not found.'];
        }
        if ($row['status'] !== 'approved') {
            return ['success' => false, 'error' => 'Only approved commissions can be marked paid.'];
        }

        $this->commissions->update($id, [
            'status'     => 'paid',
            'paid_at'    => date('Y-m-d H:i:s'),
            'updated_by' => $actingUserId,
        ]);
        $this->activity->log('sales_commissions', 'paid', $actingUserId, "Marked commission #{$id} paid", (string) $id);

        return ['success' => true];
    }

    public function deleteCommission(int $id, ?int $actingUserId): array
    {
        $row = $this->commissions->find($id);
        if (! $row) {
            return ['success' => false, 'error' => 'Commission not found.'];
        }
        if (! in_array($row['status'], ['draft', 'cancelled'], true)) {
            return ['success' => false, 'error' => 'Only draft or cancelled commissions can be deleted.'];
        }

        $this->commissions->delete($id);
        $this->activity->log('sales_commissions', 'deleted', $actingUserId, "Deleted commission #{$id}", (string) $id);

        return ['success' => true];
    }

    protected function mapTargetInput(array $input): array
    {
        return [
            'sales_rep_id'    => (int) $input['sales_rep_id'],
            'territory_id'    => ! empty($input['territory_id']) ? (int) $input['territory_id'] : null,
            'period_start'    => $input['period_start'],
            'period_end'      => $input['period_end'],
            'target_amount'   => round((float) ($input['target_amount'] ?? 0), 2),
            'achieved_amount' => round((float) ($input['achieved_amount'] ?? 0), 2),
            'status'          => $input['status'] ?? 'active',
            'notes'           => $input['notes'] ?: null,
        ];
    }

    protected function mapCommissionInput(array $input): array
    {
        $base = round((float) ($input['base_amount'] ?? 0), 2);
        $rate = round((float) ($input['rate_percent'] ?? 0), 2);
        $amount = isset($input['commission_amount']) && $input['commission_amount'] !== ''
            ? round((float) $input['commission_amount'], 2)
            : round($base * $rate / 100, 2);

        return [
            'sales_rep_id'      => (int) $input['sales_rep_id'],
            'period_start'      => $input['period_start'],
            'period_end'        => $input['period_end'],
            'base_amount'       => $base,
            'rate_percent'      => $rate,
            'commission_amount' => $amount,
            'notes'             => $input['notes'] ?: null,
        ];
    }
}
