<?php
namespace App\Services;
use App\Models\SerpCheck;use Illuminate\Support\Collection;
final class VisibilityReportService{
 public const FORMULA_VERSION='rank_weighted_v1';
 public function weight(?int $rank):string{return match(true){$rank===1=>'1.0000',$rank===2=>'0.8500',$rank===3=>'0.7500',$rank>=4&&$rank<=5=>'0.6000',$rank>=6&&$rank<=10=>'0.4000',$rank>=11&&$rank<=20=>'0.2000',$rank>=21&&$rank<=50=>'0.0800',$rank>=51&&$rank<=100=>'0.0200',default=>'0.0000'};}
 public function measurements(Collection $keywordIds,\DateTimeInterface $from,\DateTimeInterface $to):Collection{return SerpCheck::query()->whereIn('keyword_id',$keywordIds)->where('status','completed')->whereBetween('checked_at',[$from,$to])->with(['keyword.project','results'=>fn($q)=>$q->where('result_type','organic')->where('is_project_domain',true)->orderBy('position')])->orderBy('checked_at')->get()->unique(fn($c)=>$c->keyword_id.'|'.$c->checked_at?->format('Y-m-d H:i:s'))->groupBy(fn($c)=>$c->checked_at->toDateString())->map(fn($day)=>$day->groupBy('keyword_id')->map(fn($items)=>$items->last())->values())->flatten(1)->values();}
 public function rank(SerpCheck $check):?int{$rank=$check->results->min('position');return $rank&&$rank>0?$rank:null;}
 public function latest(Collection $checks):Collection{return $checks->groupBy('keyword_id')->map(fn($items)=>$items->sortByDesc('checked_at')->first())->values();}
 public function score(Collection $checks):?float{if($checks->isEmpty())return null;$sum=$checks->sum(fn($c)=>(float)$this->weight($this->rank($c)));return round(($sum/$checks->count())*100,2);}
 public function trend(Collection $checks):Collection{return $checks->groupBy(fn($c)=>$c->checked_at->toDateString())->map(fn($day,$date)=>['date'=>$date,'score'=>$this->score($day),'measured'=>$day->count()])->values();}
 public function distribution(Collection $latest,int $total):array{$ranks=$latest->map(fn($c)=>$this->rank($c));return ['top3'=>$ranks->filter(fn($r)=>$r>=1&&$r<=3)->count(),'4_10'=>$ranks->filter(fn($r)=>$r>=4&&$r<=10)->count(),'11_20'=>$ranks->filter(fn($r)=>$r>=11&&$r<=20)->count(),'21_50'=>$ranks->filter(fn($r)=>$r>=21&&$r<=50)->count(),'51_100'=>$ranks->filter(fn($r)=>$r>=51&&$r<=100)->count(),'unranked'=>$ranks->filter(fn($r)=>$r===null)->count(),'not_measured'=>max(0,$total-$latest->count())];}
 public function contributions(Collection $current,Collection $previous):Collection{$prior=$previous->keyBy('keyword_id');return $current->map(function($check)use($prior){$old=$prior->get($check->keyword_id);$delta=round(((float)$this->weight($this->rank($check))-(float)$this->weight($old?$this->rank($old):null))*100,2);return ['keyword'=>$check->keyword,'project'=>$check->keyword->project,'previous'=>$old?$this->rank($old):null,'current'=>$this->rank($check),'delta'=>$delta];});}
}
