#!/usr/bin/env bash
set -Eeuo pipefail

PROJECT_DIR="$(pwd)"

if [[ ! -f "$PROJECT_DIR/artisan" || ! -f "$PROJECT_DIR/composer.json" ]]; then
  echo "ERROR: Run this script from the Laravel Catalog project root." >&2
  exit 1
fi

STAMP="$(date +%Y%m%d_%H%M%S)"
BACKUP_DIR="$HOME/catalog-feature-backups/daily-sales-report-$STAMP"
mkdir -p "$BACKUP_DIR"

cp routes/api.php "$BACKUP_DIR/api.php.before-daily-sales-report"

mkdir -p \
  app/Services/Reports \
  app/Http/Controllers/Api/Mobile \
  resources/views/reports \
  database/migrations

cat > database/migrations/2026_08_01_230000_create_daily_sales_report_entries_table.php <<'PHP'
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('daily_sales_report_entries', function (Blueprint $table): void {
            $table->id();

            $table->foreignId('salesman_id')
                ->constrained('users')
                ->restrictOnDelete();

            $table->date('report_date');

            $table->decimal('sales_return', 12, 2)->default(0);
            $table->decimal('cash_collection', 12, 2)->default(0);
            $table->decimal('bank_transfer', 12, 2)->default(0);
            $table->decimal('cheque', 12, 2)->default(0);

            $table->text('notes')->nullable();

            $table->foreignId('created_by')
                ->nullable()
                ->constrained('users')
                ->nullOnDelete();

            $table->foreignId('updated_by')
                ->nullable()
                ->constrained('users')
                ->nullOnDelete();

            $table->timestamps();

            $table->unique(
                ['salesman_id', 'report_date'],
                'daily_sales_report_salesman_date_unique'
            );

            $table->index(['report_date', 'salesman_id']);
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('daily_sales_report_entries');
    }
};
PHP

cat > app/Models/DailySalesReportEntry.php <<'PHP'
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class DailySalesReportEntry extends Model
{
    protected $fillable = [
        'salesman_id',
        'report_date',
        'sales_return',
        'cash_collection',
        'bank_transfer',
        'cheque',
        'notes',
        'created_by',
        'updated_by',
    ];

    protected function casts(): array
    {
        return [
            'report_date' => 'date',
            'sales_return' => 'decimal:2',
            'cash_collection' => 'decimal:2',
            'bank_transfer' => 'decimal:2',
            'cheque' => 'decimal:2',
        ];
    }

    public function salesman(): BelongsTo
    {
        return $this->belongsTo(User::class, 'salesman_id');
    }

    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    public function updater(): BelongsTo
    {
        return $this->belongsTo(User::class, 'updated_by');
    }
}
PHP

cat > app/Services/Reports/DailySalesReportService.php <<'PHP'
<?php

namespace App\Services\Reports;

use App\Models\CustomerOrder;
use App\Models\DailySalesReportEntry;
use App\Models\User;
use Carbon\CarbonImmutable;
use Illuminate\Support\Collection;

class DailySalesReportService
{
    public function build(
        User $salesman,
        CarbonImmutable $month
    ): array {
        $month = $month->startOfMonth();

        $start = $month->startOfDay();
        $end = $month->endOfMonth()->endOfDay();

        $salesByDate = CustomerOrder::query()
            ->where('salesman_id', $salesman->id)
            ->whereNotNull('confirmed_at')
            ->whereBetween('confirmed_at', [$start, $end])
            ->selectRaw(
                'DATE(confirmed_at) as report_date, SUM(grand_total) as total'
            )
            ->groupByRaw('DATE(confirmed_at)')
            ->pluck('total', 'report_date');

        $entries = DailySalesReportEntry::query()
            ->where('salesman_id', $salesman->id)
            ->whereBetween('report_date', [
                $start->toDateString(),
                $end->toDateString(),
            ])
            ->get()
            ->keyBy(
                fn (DailySalesReportEntry $entry): string =>
                    $entry->report_date->toDateString()
            );

        $rows = [];
        $weekNumber = 1;
        $weekTotals = $this->emptyTotals();
        $grandTotals = $this->emptyTotals();

        for (
            $date = $start;
            $date->lessThanOrEqualTo($end);
            $date = $date->addDay()
        ) {
            if ($date->isSunday()) {
                $rows[] = [
                    'type' => 'off',
                    'date' => $date->toDateString(),
                    'date_label' => $date->format('d/m/Y'),
                    'day_name' => $date->format('l'),
                    'label' => $date->format('d/m/Y').' - SUNDAY OFF',
                ];

                continue;
            }

            $dateKey = $date->toDateString();

            /** @var DailySalesReportEntry|null $entry */
            $entry = $entries->get($dateKey);

            $day = [
                'wiwu_sales' => $this->money(
                    $salesByDate->get($dateKey, 0)
                ),
                'sales_return' => $this->money(
                    $entry?->sales_return ?? 0
                ),
                'cash_collection' => $this->money(
                    $entry?->cash_collection ?? 0
                ),
                'bank_transfer' => $this->money(
                    $entry?->bank_transfer ?? 0
                ),
                'cheque' => $this->money(
                    $entry?->cheque ?? 0
                ),
            ];

            $day['total_collection'] = $this->money(
                $day['cash_collection']
                + $day['bank_transfer']
                + $day['cheque']
            );

            $rows[] = [
                'type' => 'day',
                'date' => $dateKey,
                'date_label' => $date->format('d/m/Y'),
                'day_name' => $date->format('l'),
                'is_today' => $date->isToday(),
                'notes' => $entry?->notes,
                ...$day,
            ];

            $this->addTotals($weekTotals, $day);
            $this->addTotals($grandTotals, $day);

            if (
                $date->isSaturday()
                || $date->isSameDay($end)
            ) {
                $rows[] = [
                    'type' => 'week_total',
                    'week_number' => $weekNumber,
                    'label' => 'WEEK TOTAL',
                    ...$weekTotals,
                ];

                $weekNumber++;
                $weekTotals = $this->emptyTotals();
            }
        }

        return [
            'month' => $month->format('Y-m'),
            'month_label' => $month->format('F Y'),
            'salesman' => [
                'id' => $salesman->id,
                'name' => $salesman->name,
            ],
            'area' => $this->areaLabel($salesman),
            'currency' => 'AED',
            'rows' => $rows,
            'totals' => $grandTotals,
            'generated_at' => now()->toIso8601String(),
        ];
    }

    private function emptyTotals(): array
    {
        return [
            'wiwu_sales' => 0.0,
            'sales_return' => 0.0,
            'cash_collection' => 0.0,
            'bank_transfer' => 0.0,
            'cheque' => 0.0,
            'total_collection' => 0.0,
        ];
    }

    private function addTotals(
        array &$totals,
        array $values
    ): void {
        foreach (array_keys($totals) as $key) {
            $totals[$key] = $this->money(
                $totals[$key] + ($values[$key] ?? 0)
            );
        }
    }

    private function money(mixed $value): float
    {
        return round((float) $value, 2);
    }

    private function areaLabel(User $salesman): string
    {
        /** @var Collection<int, string> $areas */
        $areas = $salesman->areas()
            ->where('areas.is_active', true)
            ->orderBy('areas.sort_order')
            ->orderBy('areas.name')
            ->pluck('areas.name');

        $label = $areas
            ->filter()
            ->implode(', ');

        return $label !== ''
            ? $label
            : 'Not assigned';
    }
}
PHP

cat > app/Http/Controllers/Api/Mobile/DailySalesReportController.php <<'PHP'
<?php

namespace App\Http\Controllers\Api\Mobile;

use App\Http\Controllers\Controller;
use App\Models\DailySalesReportEntry;
use App\Models\User;
use App\Services\Reports\DailySalesReportService;
use Carbon\CarbonImmutable;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class DailySalesReportController extends Controller
{
    public function show(
        Request $request,
        DailySalesReportService $service
    ): JsonResponse {
        /** @var User $user */
        $user = $request->user();

        $month = $this->resolveMonth(
            $request->query('month')
        );

        if (! $month) {
            return response()->json([
                'success' => false,
                'message' => 'The month must use the YYYY-MM format.',
            ], 422);
        }

        return response()->json([
            'success' => true,
            'data' => $service->build($user, $month),
        ]);
    }

    public function saveEntry(
        Request $request,
        DailySalesReportService $service
    ): JsonResponse {
        /** @var User $user */
        $user = $request->user();

        $validated = $request->validate([
            'date' => [
                'required',
                'date_format:Y-m-d',
            ],
            'sales_return' => [
                'nullable',
                'numeric',
                'min:0',
            ],
            'cash_collection' => [
                'nullable',
                'numeric',
                'min:0',
            ],
            'bank_transfer' => [
                'nullable',
                'numeric',
                'min:0',
            ],
            'cheque' => [
                'nullable',
                'numeric',
                'min:0',
            ],
            'notes' => [
                'nullable',
                'string',
                'max:2000',
            ],
        ]);

        $date = CarbonImmutable::createFromFormat(
            'Y-m-d',
            $validated['date'],
            config('app.timezone')
        );

        if (! $date || $date->format('Y-m-d') !== $validated['date']) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid report date.',
            ], 422);
        }

        if ($date->isSunday()) {
            return response()->json([
                'success' => false,
                'message' => 'Sunday is marked as a day off.',
            ], 422);
        }

        $entry = DailySalesReportEntry::query()
            ->firstOrNew([
                'salesman_id' => $user->id,
                'report_date' => $date->toDateString(),
            ]);

        if (! $entry->exists) {
            $entry->created_by = $user->id;
        }

        $entry->fill([
            'sales_return' => $validated['sales_return'] ?? 0,
            'cash_collection' => $validated['cash_collection'] ?? 0,
            'bank_transfer' => $validated['bank_transfer'] ?? 0,
            'cheque' => $validated['cheque'] ?? 0,
            'notes' => $validated['notes'] ?? null,
            'updated_by' => $user->id,
        ]);

        $entry->save();

        return response()->json([
            'success' => true,
            'message' => 'Daily report entry saved.',
            'data' => $service->build(
                $user,
                $date->startOfMonth()
            ),
        ]);
    }

    private function resolveMonth(mixed $value): ?CarbonImmutable
    {
        $monthValue = trim(
            (string) ($value ?: now()->format('Y-m'))
        );

        if (! preg_match('/^\d{4}-\d{2}$/', $monthValue)) {
            return null;
        }

        try {
            $month = CarbonImmutable::createFromFormat(
                'Y-m-d',
                $monthValue.'-01',
                config('app.timezone')
            );
        } catch (\Throwable) {
            return null;
        }

        if (! $month || $month->format('Y-m') !== $monthValue) {
            return null;
        }

        return $month->startOfMonth();
    }
}
PHP

cat > app/Http/Controllers/Api/Mobile/DailySalesReportPdfController.php <<'PHP'
<?php

namespace App\Http\Controllers\Api\Mobile;

use App\Http\Controllers\Controller;
use App\Models\CompanySetting;
use App\Models\User;
use App\Services\Reports\DailySalesReportService;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;

class DailySalesReportPdfController extends Controller
{
    public function __invoke(
        Request $request,
        DailySalesReportService $service
    ) {
        /** @var User $user */
        $user = $request->user();

        $monthValue = trim(
            (string) $request->query(
                'month',
                now()->format('Y-m')
            )
        );

        if (! preg_match('/^\d{4}-\d{2}$/', $monthValue)) {
            return response()->json([
                'success' => false,
                'message' => 'The month must use the YYYY-MM format.',
            ], 422);
        }

        try {
            $month = CarbonImmutable::createFromFormat(
                'Y-m-d',
                $monthValue.'-01',
                config('app.timezone')
            );
        } catch (\Throwable) {
            $month = null;
        }

        if (! $month || $month->format('Y-m') !== $monthValue) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid report month.',
            ], 422);
        }

        $report = $service->build(
            $user,
            $month->startOfMonth()
        );

        $company = CompanySetting::current();

        $pdf = app('dompdf.wrapper')
            ->loadView(
                'reports.daily-sales-pdf',
                [
                    'report' => $report,
                    'company' => $company,
                ]
            )
            ->setPaper('a4', 'portrait');

        $safeSalesman = preg_replace(
            '/[^A-Za-z0-9._-]+/',
            '_',
            (string) $user->name
        ) ?: 'salesman';

        $filename = sprintf(
            'daily_sales_report_%s_%s.pdf',
            $safeSalesman,
            $month->format('Y_m')
        );

        return response(
            $pdf->output(),
            200,
            [
                'Content-Type' => 'application/pdf',
                'Content-Disposition' =>
                    'inline; filename="'.$filename.'"',
                'Cache-Control' =>
                    'private, no-store, max-age=0',
            ]
        );
    }
}
PHP

cat > resources/views/reports/daily-sales-pdf.blade.php <<'BLADE'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">

    <title>
        Daily Sales Report - {{ $report['month_label'] }}
    </title>

    <style>
        @page {
            margin: 5mm;
        }

        * {
            box-sizing: border-box;
        }

        body {
            margin: 0;
            color: #111827;
            font-family: DejaVu Sans, sans-serif;
            font-size: 6.3px;
            line-height: 1.05;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            table-layout: fixed;
        }

        .title-table td {
            height: 9mm;
            border: 1px solid #1f2937;
            background: #fff200;
            font-size: 13px;
            font-weight: bold;
            text-align: center;
            vertical-align: middle;
        }

        .meta-table td {
            height: 10mm;
            padding: 2px 3px;
            border: 1px solid #1f2937;
            font-size: 7.5px;
            font-weight: bold;
            text-align: center;
            vertical-align: middle;
        }

        .meta-table .large {
            font-size: 10px;
        }

        .spacer {
            height: 1.5mm;
        }

        .report-table th,
        .report-table td {
            height: 4.6mm;
            padding: 1px 2px;
            border: 0.45px solid #1f2937;
            text-align: center;
            vertical-align: middle;
            white-space: nowrap;
        }

        .report-table th {
            height: 7.2mm;
            background: #48b8e8;
            font-size: 6.2px;
            font-weight: bold;
        }

        .report-table .date {
            text-align: left;
        }

        .report-table .off-row td {
            height: 4.9mm;
            background: #fb923c;
            font-weight: bold;
            text-align: center;
        }

        .report-table .week-row td {
            height: 4.9mm;
            background: #9cc3e6;
            font-weight: bold;
        }

        .report-table .week-row .label {
            color: #dc2626;
            text-align: left;
        }

        .report-table .grand-row td {
            height: 4.9mm;
            background: #e89a9a;
            font-weight: bold;
        }

        .report-table .grand-row .label {
            background: #d98282;
            color: #ffffff;
        }

        .footer {
            margin-top: 1mm;
            color: #64748b;
            font-size: 5.4px;
            text-align: center;
        }
    </style>
</head>

<body>
@php
    $formatAmount = static function (
        mixed $value,
        bool $blankZero = false
    ): string {
        $amount = round((float) $value, 2);

        if ($blankZero && abs($amount) < 0.00001) {
            return '';
        }

        if (abs($amount - round($amount)) < 0.00001) {
            return number_format($amount, 0);
        }

        return number_format($amount, 2);
    };
@endphp

<table class="title-table">
    <tr>
        <td>
            OUTDOOR DAILY SALES REPORT
        </td>
    </tr>
</table>

<table class="meta-table">
    <tr>
        <td style="width: 19%;" class="large">
            {{ $report['month_label'] }}
        </td>

        <td style="width: 15%;">
            Salesman
        </td>

        <td style="width: 32%;" class="large">
            {{ $report['salesman']['name'] }}
        </td>

        <td style="width: 14%;">
            Area :
        </td>

        <td style="width: 20%;" class="large">
            {{ $report['area'] }}
        </td>
    </tr>
</table>

<div class="spacer"></div>

<table class="report-table">
    <thead>
        <tr>
            <th style="width: 17%;">Date</th>
            <th style="width: 13.5%;">WIWU Sales</th>
            <th style="width: 13.5%;">Sales Return</th>
            <th style="width: 15%;">Cash Collection</th>
            <th style="width: 15%;">Bank Transfer</th>
            <th style="width: 11.5%;">Cheque</th>
            <th style="width: 14.5%;">Total Collection</th>
        </tr>
    </thead>

    <tbody>
        @foreach($report['rows'] as $row)
            @if($row['type'] === 'off')
                <tr class="off-row">
                    <td colspan="7">
                        {{ $row['label'] }}
                    </td>
                </tr>
            @elseif($row['type'] === 'week_total')
                <tr class="week-row">
                    <td class="label">
                        {{ $row['label'] }}
                    </td>

                    <td>{{ $formatAmount($row['wiwu_sales']) }}</td>
                    <td>{{ $formatAmount($row['sales_return']) }}</td>
                    <td>{{ $formatAmount($row['cash_collection']) }}</td>
                    <td>{{ $formatAmount($row['bank_transfer']) }}</td>
                    <td>{{ $formatAmount($row['cheque']) }}</td>
                    <td>{{ $formatAmount($row['total_collection']) }}</td>
                </tr>
            @else
                <tr>
                    <td class="date">
                        {{ $row['date_label'] }}
                    </td>

                    <td>
                        {{ $formatAmount($row['wiwu_sales'], true) }}
                    </td>

                    <td>
                        {{ $formatAmount($row['sales_return'], true) }}
                    </td>

                    <td>
                        {{ $formatAmount($row['cash_collection'], true) }}
                    </td>

                    <td>
                        {{ $formatAmount($row['bank_transfer'], true) }}
                    </td>

                    <td>
                        {{ $formatAmount($row['cheque'], true) }}
                    </td>

                    <td>
                        {{ $formatAmount($row['total_collection']) }}
                    </td>
                </tr>
            @endif
        @endforeach

        <tr class="grand-row">
            <td class="label">
                GRAND TOTAL
            </td>

            <td>{{ $formatAmount($report['totals']['wiwu_sales']) }}</td>
            <td>{{ $formatAmount($report['totals']['sales_return']) }}</td>
            <td>{{ $formatAmount($report['totals']['cash_collection']) }}</td>
            <td>{{ $formatAmount($report['totals']['bank_transfer']) }}</td>
            <td>{{ $formatAmount($report['totals']['cheque']) }}</td>
            <td>{{ $formatAmount($report['totals']['total_collection']) }}</td>
        </tr>
    </tbody>
</table>

<div class="footer">
    {{ $company->company_name ?? config('app.name') }}
    -
    Generated by SNYT Salesman Van
    -
    {{ now()->format('d/m/Y H:i') }}
</div>
</body>
</html>
BLADE

python3 - <<'PY'
from pathlib import Path

path = Path("routes/api.php")
text = path.read_text()

uses = """use App\\Http\\Controllers\\Api\\Mobile\\DailySalesReportController;
use App\\Http\\Controllers\\Api\\Mobile\\DailySalesReportPdfController;
"""

anchor = "use App\\Http\\Controllers\\Api\\Mobile\\DashboardController;\n"

if "DailySalesReportController" not in text:
    if anchor not in text:
        raise SystemExit("Could not find the route import insertion point.")
    text = text.replace(anchor, anchor + uses, 1)

routes = """
        Route::get('/reports/daily-sales', [DailySalesReportController::class, 'show']);
        Route::post('/reports/daily-sales/entry', [DailySalesReportController::class, 'saveEntry']);
        Route::get('/reports/daily-sales/pdf', DailySalesReportPdfController::class);
"""

route_anchor = "        Route::get('/dashboard', [DashboardController::class, 'index']);\n"

if "/reports/daily-sales" not in text:
    if route_anchor not in text:
        raise SystemExit("Could not find the route insertion point.")
    text = text.replace(route_anchor, route_anchor + routes, 1)

path.write_text(text)
PY

PHP_FILES=(
  database/migrations/2026_08_01_230000_create_daily_sales_report_entries_table.php
  app/Models/DailySalesReportEntry.php
  app/Services/Reports/DailySalesReportService.php
  app/Http/Controllers/Api/Mobile/DailySalesReportController.php
  app/Http/Controllers/Api/Mobile/DailySalesReportPdfController.php
  routes/api.php
)

for file in "${PHP_FILES[@]}"; do
  php -l "$file" >/dev/null
  echo "PHP syntax OK: $file"
done

echo
echo "Backend files installed."
echo "Route backup: $BACKUP_DIR/api.php.before-daily-sales-report"
echo
echo "Next commands:"
echo "  php artisan migrate --force"
echo "  php artisan optimize:clear"
echo "  php artisan route:list | grep daily-sales"
