<?php

declare(strict_types=1);

namespace App\Controllers\Public;

use App\Core\BaseController;
use App\Core\Database;
use App\Core\Request;
use App\Core\Response;
use App\Core\Session;
use App\Core\Validator;
use App\Services\StripeService;
use App\Services\SubscriptionService;

/**
 * SignupController
 *
 * Lives on the root/marketing domain (NOT behind TenantMiddleware —
 * there's no tenant yet, that's the point of this controller). A
 * company fills in their details here, gets a subdomain reserved in a
 * 'trialing' state, then picks how to actually pay: Stripe card
 * checkout, or a subscription code from the platform owner.
 */
final class SignupController extends BaseController
{
    public function showForm(Request $request): Response
    {
        return $this->view('public/signup', [
            'title' => 'Start your CRM',
            'appDomain' => (string) config('app.domain', 'yourapp.com'),
        ], useLayout: false);
    }

    public function submit(Request $request): Response
    {
        $validator = Validator::make($request->all(), [
            'company_name' => 'required|string|max:191',
            'subdomain' => 'required|string|max:63',
            'first_name' => 'required|string|max:100',
            'last_name' => 'required|string|max:100',
            'email' => 'required|email',
            'password' => 'required|string|min:10',
        ]);

        if ($validator->fails()) {
            return $this->withErrors($request, $validator->errors(), 'signup');
        }

        $data = $validator->validated();

        $existingEmail = Database::connection()->prepare('SELECT 1 FROM users WHERE email = :email');
        $existingEmail->execute(['email' => $data['email']]);
        if ($existingEmail->fetchColumn() !== false) {
            return $this->withErrors($request, ['email' => 'That email is already in use.'], 'signup');
        }

        try {
            $result = (new SubscriptionService())->registerTenant(
                companyName: $data['company_name'],
                subdomainSlug: $data['subdomain'],
                ownerFirstName: $data['first_name'],
                ownerLastName: $data['last_name'],
                ownerEmail: $data['email'],
                ownerPasswordHash: password_hash($data['password'], PASSWORD_ARGON2ID),
            );
        } catch (\RuntimeException $e) {
            return $this->withErrors($request, ['subdomain' => $e->getMessage()], 'signup');
        }

        // Not logged into the tenant app yet (that only happens on its
        // own subdomain) — stash which tenant this browser just created
        // so the activation step below can find it again.
        Session::flash('_new_business_line_id', $result['business_line_id']);

        return $this->redirect('signup/activate/' . $result['business_line_id']);
    }

    public function showActivate(Request $request, int $businessLineId): Response
    {
        $tenant = $this->findTenantOr404($businessLineId);

        return $this->view('public/signup-activate', [
            'title' => 'Activate your subscription',
            'tenant' => $tenant,
            'appDomain' => (string) config('app.domain', 'yourapp.com'),
            'stripeConfigured' => StripeService::configured(),
        ], useLayout: false);
    }

    /** Option A: pay by card. Redirects to Stripe's hosted Checkout page. */
    public function checkout(Request $request, int $businessLineId): Response
    {
        $tenant = $this->findTenantOr404($businessLineId);
        $appDomain = (string) config('app.domain', '');
        $tenantUrl = "https://{$tenant['slug']}.{$appDomain}";

        try {
            $url = (new StripeService())->createCheckoutSession(
                businessLineId: $businessLineId,
                customerEmail: (string) $tenant['billing_email'],
                successUrl: $tenantUrl . '/login?activated=1',
                cancelUrl: base_url('signup/activate/' . $businessLineId),
            );
        } catch (\RuntimeException $e) {
            return $this->withErrors($request, ['stripe' => $e->getMessage()], 'signup/activate/' . $businessLineId);
        }

        return Response::redirect($url);
    }

    /** Option B: redeem a code from the platform owner instead of paying. */
    public function redeemCode(Request $request, int $businessLineId): Response
    {
        $tenant = $this->findTenantOr404($businessLineId);

        $validator = Validator::make($request->all(), ['code' => 'required|string|max:40']);
        if ($validator->fails()) {
            return $this->withErrors($request, $validator->errors(), 'signup/activate/' . $businessLineId);
        }

        try {
            (new SubscriptionService())->redeemCode($validator->validated()['code'], $businessLineId, isNewSignup: true);
        } catch (\RuntimeException $e) {
            return $this->withErrors($request, ['code' => $e->getMessage()], 'signup/activate/' . $businessLineId);
        }

        $appDomain = (string) config('app.domain', '');

        return Response::redirect("https://{$tenant['slug']}.{$appDomain}/login?activated=1");
    }

    private function findTenantOr404(int $businessLineId): array
    {
        $stmt = Database::connection()->prepare('SELECT * FROM business_lines WHERE id = :id');
        $stmt->execute(['id' => $businessLineId]);
        $tenant = $stmt->fetch(\PDO::FETCH_ASSOC);

        if ($tenant === false) {
            throw new \RuntimeException('Unknown company.');
        }

        return $tenant;
    }
}
