<?php

namespace App\Http\Controllers;

use App\Models\Contact;
use App\Models\EmailMessage;
use App\Models\Group;
use App\Models\Message;
use App\Models\Reminder;
use App\Models\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Symfony\Component\HttpFoundation\StreamedResponse;
use ZipArchive;

class WorkspaceExportController extends Controller
{
    /**
     * Stream a ZIP containing CSV exports of every table in the current
     * workspace. Lets buyers (or their customers) walk away with their data.
     */
    public function download(Request $request): StreamedResponse
    {
        Gate::authorize('viewAny', Contact::class);

        $team = $request->user()->currentTeam;
        abort_unless($team, 404);

        $tmpZip = tempnam(sys_get_temp_dir(), 'lc-export-') . '.zip';

        $zip = new ZipArchive();
        $zip->open($tmpZip, ZipArchive::CREATE | ZipArchive::OVERWRITE);

        $exports = [
            'contacts.csv' => [
                ['id', 'name', 'email', 'phone', 'company', 'job_title', 'website', 'address', 'notes', 'lifecycle_stage', 'group_id', 'created_at'],
                Contact::withoutTeamScope()->where('team_id', $team->id)->get()->map(fn ($c) => [
                    $c->id, $c->name, $c->email, $c->phone, $c->company, $c->job_title,
                    $c->website, $c->address, $c->notes, $c->lifecycle_stage, $c->group_id, (string) $c->created_at,
                ]),
            ],
            'messages.csv' => [
                ['id', 'contact_id', 'channel', 'direction', 'status', 'from_number', 'to_number', 'body', 'sent_at'],
                Message::where('team_id', $team->id)->get()->map(fn ($m) => [
                    $m->id, $m->contact_id, $m->channel, $m->direction, $m->status,
                    $m->from_number, $m->to_number, $m->body, (string) $m->sent_at,
                ]),
            ],
            'emails.csv' => [
                ['id', 'contact_id', 'subject', 'from_email', 'to_email', 'status', 'opens_count', 'sent_at'],
                EmailMessage::where('team_id', $team->id)->get()->map(fn ($e) => [
                    $e->id, $e->contact_id, $e->subject, $e->from_email, $e->to_email,
                    $e->status, $e->opens_count ?? 0, (string) $e->sent_at,
                ]),
            ],
            'reminders.csv' => [
                ['id', 'contact_id', 'title', 'description', 'remind_at', 'status', 'created_at'],
                Reminder::where('team_id', $team->id)->get()->map(fn ($r) => [
                    $r->id, $r->contact_id, $r->title, $r->description,
                    (string) $r->remind_at, $r->status, (string) $r->created_at,
                ]),
            ],
            'groups.csv' => [
                ['id', 'name', 'color'],
                Group::withoutTeamScope()->where('team_id', $team->id)->get()->map(fn ($g) => [$g->id, $g->name, $g->color]),
            ],
            'tags.csv' => [
                ['id', 'name', 'slug'],
                Tag::withoutTeamScope()->where('team_id', $team->id)->get()->map(fn ($t) => [$t->id, $t->name, $t->slug]),
            ],
        ];

        foreach ($exports as $filename => [$header, $rows]) {
            $zip->addFromString($filename, $this->toCsv($header, $rows));
        }

        // Manifest with counts so the buyer knows what they got.
        $zip->addFromString('README.txt',
            "LaraContact workspace export\n" .
            "Workspace: {$team->name}\n" .
            "Generated: " . now()->toIso8601String() . "\n\n" .
            "Files:\n" .
            collect($exports)->map(fn ($e, $f) => "- {$f} ({$e[1]->count()} rows)")->implode("\n") . "\n"
        );

        $zip->close();

        $stem = preg_replace('/[^A-Za-z0-9-]/', '-', strtolower($team->name));
        $name = "laracontact-export-{$stem}-".now()->format('Ymd-His').".zip";

        return response()->streamDownload(function () use ($tmpZip) {
            readfile($tmpZip);
            @unlink($tmpZip);
        }, $name, ['Content-Type' => 'application/zip']);
    }

    /**
     * Turn a header + row collection into a CSV string. Uses fputcsv on an
     * in-memory stream so we don't touch the filesystem.
     */
    protected function toCsv(array $header, $rows): string
    {
        $fp = fopen('php://temp', 'r+');
        fputcsv($fp, $header);
        foreach ($rows as $row) {
            fputcsv($fp, array_map(fn ($v) => $v === null ? '' : (string) $v, $row));
        }
        rewind($fp);
        $csv = stream_get_contents($fp);
        fclose($fp);
        return $csv;
    }
}
