<?php
namespace App\Http\Controllers;use App\Http\Requests\{StoreCompetitorRequest,VisibilityReportRequest};use App\Models\{Project,ProjectCompetitor};use App\Services\{CompetitorAuditLogger,CompetitorReportService};use Illuminate\Database\QueryException;use Illuminate\Http\RedirectResponse;use Illuminate\Validation\ValidationException;use Illuminate\View\View;
class CompetitorController extends Controller{public function index(VisibilityReportRequest$r,CompetitorReportService$s):View{$projects=$r->user()->projects()->active()->with(['competitors'=>fn($q)=>$q->orderBy('name')])->orderBy('name')->get();$project=$r->filled('project')?$projects->firstWhere('ulid',$r->input('project')):$projects->first();if($r->filled('project'))abort_unless($project,404);$competitors=$project?->competitors?->where('status','active')->values()??collect();$data=$project?$s->compare($project,$competitors,now()->parse($r->input('from'))->startOfDay(),now()->parse($r->input('to'))->endOfDay()):null;return view('reports.competitors',compact('projects','project','competitors','data'));}public function store(StoreCompetitorRequest$r,Project$p,CompetitorAuditLogger$a):RedirectResponse{$this->guard($r,$p);if($p->competitors()->active()->count()>=(int)config('serp.competitor_limit',10))throw ValidationException::withMessages(['domain'=>__('competitors.limit')]);if($r->input('normalized_domain')===$p->domain)throw ValidationException::withMessages(['domain'=>__('competitors.self_domain')]);try{$c=$p->competitors()->create($r->safe()->only(['name','domain','normalized_domain'])+['created_by'=>$r->user()->id]);}catch(QueryException){throw ValidationException::withMessages(['domain'=>__('competitors.duplicate')]);}$a->record('created',$c,$r->user());return back()->with('status',__('competitors.created'));}public function update(StoreCompetitorRequest$r,Project$p,ProjectCompetitor$c,CompetitorAuditLogger$a):RedirectResponse{$this->guard($r,$p,$c);if($r->input('normalized_domain')===$p->domain)throw ValidationException::withMessages(['domain'=>__('competitors.self_domain')]);$before=$c->attributesToArray();try{$c->update($r->safe()->only(['name','domain','normalized_domain']));}catch(QueryException){throw ValidationException::withMessages(['domain'=>__('competitors.duplicate')]);}$a->record('updated',$c,$r->user(),$before);return back()->with('status',__('competitors.updated'));}public function archive(VisibilityReportRequest$r,Project$p,ProjectCompetitor$c,CompetitorAuditLogger$a):RedirectResponse{$this->guard($r,$p,$c);$before=$c->attributesToArray();$c->forceFill(['status'=>'archived','archived_at'=>now()])->save();$a->record('archived',$c,$r->user(),$before);return back();}public function restore(VisibilityReportRequest$r,Project$p,ProjectCompetitor$c,CompetitorAuditLogger$a):RedirectResponse{$this->guard($r,$p,$c);$before=$c->attributesToArray();$c->forceFill(['status'=>'active','archived_at'=>null])->save();$a->record('restored',$c,$r->user(),$before);return back();}public function show(VisibilityReportRequest$r,Project$p,ProjectCompetitor$c,CompetitorReportService$s):View{$this->guard($r,$p,$c);$data=$s->compare($p,collect([$c]),now()->subDays(29),now());return view('reports.competitor-show',compact('p','c','data'));}private function guard($r,Project$p,?ProjectCompetitor$c=null):void{abort_unless($p->user_id===$r->user()->id,404);if($c)abort_unless($c->project_id===$p->id,404);}}
