<?php
namespace App\Services;
use App\Models\{Project,User,Plan,ServicePeriod,Assignment,Activity,Task};
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
class ProjectFlow {
 public function create(User $actor,array $data):Project {
  if(!$actor->isManager()){abort_unless($actor->role==='customer',403);$p=Project::create(['form_schema'=>Settings::get('intake_schema',config('intake')),'customer_id'=>$actor->id,'department_id'=>$actor->department_id,'name'=>$data['name'],'site_url'=>$data['site_url']??null,'description'=>$data['description']??null]);app(Notify::class)->event('project_requested',$p,[],"request:$p->id");return $p;}
  Access::manage($actor);$plan=Plan::where('kind','mentoring')->findOrFail($data['plan_id']);$mentor=User::where('active',true)->where('role','mentor')->findOrFail($data['mentor_id']);$customer=User::where('role','customer')->findOrFail($data['customer_id']);
  abort_unless($actor->role==='admin'||$mentor->department_id===$actor->department_id&&$customer->department_id===$actor->department_id&&$actor->department_id,403);
  if(!empty($data['department_id']))abort_unless((int)$data['department_id']===$mentor->department_id,422,'منتور باید عضو بخش انتخابی پروژه باشد.');
  $start=Dates::parse($data['start_date']);$end=Dates::parse($data['end_date'],true);if($end->lte($start))throw ValidationException::withMessages(['end_date'=>'پایان باید پس از شروع باشد.']);
  return DB::transaction(function()use($data,$plan,$mentor,$customer,$start,$end,$actor){
   $snapshot=$plan->only(['id','name','version','days','price','quotas','features']);
   $p=Project::create(['form_schema'=>Settings::get('intake_schema',config('intake')),'customer_id'=>$customer->id,'mentor_id'=>$mentor->id,'department_id'=>$mentor->department_id,'plan_id'=>$plan->id,'name'=>$data['name'],'site_url'=>$data['site_url']??null,'description'=>$data['description']??null,'internal_note'=>$data['internal_note']??null,'starts_at'=>$start,'expires_at'=>$end,'plan_snapshot'=>$snapshot,'status'=>'waiting_info','credentials'=>!empty($data['wp_password'])?['login_url'=>$data['login_url'],'username'=>$data['wp_username'],'password'=>$data['wp_password']]:null]);
   ServicePeriod::create(['project_id'=>$p->id,'starts_at'=>$start,'expires_at'=>$end,'snapshot'=>$snapshot]);Assignment::create(['project_id'=>$p->id,'mentor_id'=>$mentor->id,'starts_at'=>now(),'reason'=>'تخصیص اولیه']);
   $this->activity($p,$actor,'created','پروژه شما ایجاد شد؛ خوشحالیم که همراه شما هستیم.');
   app(Notify::class)->event('project_created',$p,[],"project:$p->id:created");return $p;
  });
 }
 public function activate(User $actor,Project $project,array $data):void {
  Access::manage($actor,$project);
  $plan=Plan::where('kind','mentoring')->findOrFail($data['plan_id']);
  $mentor=User::where('role','mentor')->where('active',true)->findOrFail($data['mentor_id']);
  abort_unless($actor->role==='admin'||$actor->department_id&&$mentor->department_id===$actor->department_id,403);
  $start=Dates::parse($data['start_date']);$end=Dates::parse($data['end_date'],true);
  abort_unless($end->gt($start),422,'تاریخ پایان باید پس از شروع باشد.');
  DB::transaction(function()use($actor,$project,$data,$plan,$mentor,$start,$end){
   $p=Project::lockForUpdate()->findOrFail($project->id);abort_unless($p->status==='requested',422);
   $snapshot=$plan->only(['id','name','version','days','price','quotas','features']);
   $p->update(['form_schema'=>$p->form_schema??Settings::get('intake_schema',config('intake')),'mentor_id'=>$mentor->id,'department_id'=>$mentor->department_id,'plan_id'=>$plan->id,'plan_snapshot'=>$snapshot,'starts_at'=>$start,'expires_at'=>$end,'status'=>'waiting_info','internal_note'=>$data['internal_note']??null]);
   ServicePeriod::create(['project_id'=>$p->id,'starts_at'=>$start,'expires_at'=>$end,'snapshot'=>$snapshot]);
   Assignment::create(['project_id'=>$p->id,'mentor_id'=>$mentor->id,'starts_at'=>now(),'reason'=>'تأیید درخواست مشتری']);
   $this->activity($p,$actor,'created','درخواست شما تأیید شد؛ آماده همراهی شما هستیم.');
   app(Notify::class)->event('project_created',$p,[],"project:$p->id:created");Access::audit('project_activated',$p->id);
  });
 }
 public function gift(User $actor,Project $project,int $days,string $reason):void {
  Access::manage($actor,$project);abort_unless($actor->canAdmin('pricing'),403);
  DB::transaction(function()use($actor,$project,$days,$reason){$p=Project::lockForUpdate()->findOrFail($project->id);abort_unless($days>0&&$days<=365&&!$p->paused_at&&!in_array($p->status,['requested','cancelled','archived'])&&$p->mentor?->active,422);
   $start=$p->expires_at->isFuture()?$p->expires_at->copy():now();$end=$start->copy()->setTimezone('Asia/Tehran')->addDays($days)->utc();
   ServicePeriod::create(['project_id'=>$p->id,'starts_at'=>$start,'expires_at'=>$end,'snapshot'=>['name'=>'همراهی هدیه','days'=>$days,'price'=>0,'quotas'=>['products'=>0,'pages'=>0,'categories'=>0,'variants'=>0],'gift'=>true,'actor_id'=>$actor->id,'reason'=>$reason]]);
   $p->update(['expires_at'=>$end]);$this->activity($p,$actor,'renewed','زمان همراهی به مدت '.fa_num($days).' روز تمدید هدیه شد.');Access::audit('gift_period',$p->id,['days'=>$days,'reason'=>$reason]);app(Notify::class)->event('renewed',$p,[],"gift:$p->id:".$end->timestamp);
  });
 }
 public function dates(User $actor,Project $project,string $from,string $to,string $reason):void {
  Access::manage($actor,$project);$start=Dates::parse($from);$end=Dates::parse($to,true);abort_unless($end->gt($start),422);
  DB::transaction(function()use($actor,$project,$start,$end,$reason){$p=Project::lockForUpdate()->findOrFail($project->id);abort_unless(!$p->paused_at&&!in_array($p->status,['requested','cancelled','archived'])&&$p->periods()->count()===1,422,'پس از تمدید، از دوره هدیه برای افزایش زمان استفاده کنید.');$old=['starts_at'=>$p->starts_at,'expires_at'=>$p->expires_at];$p->periods()->first()->update(['starts_at'=>$start,'expires_at'=>$end]);$p->update(['starts_at'=>$start,'expires_at'=>$end]);Access::audit('dates_changed',$p->id,['before'=>$old,'reason'=>$reason]);$this->activity($p,$actor,'dates_changed','بازه زمانی پروژه با توضیح مدیر اصلاح شد: '.$reason);});
 }
 public function activity(Project $p,?User $u,string $type,string $summary,bool $effective=false,bool $visible=true):void {
  Activity::create(['project_id'=>$p->id,'user_id'=>$u?->id,'type'=>$type,'summary'=>$summary,'visible'=>$visible,'effective'=>$effective]);
  if($effective){$values=['last_activity_at'=>now()];if($u)$values[$u->id===$p->customer_id?'last_customer_at':'last_mentor_at']=now();$p->update($values);}
 }
 public function assign(User $actor,Project $project,int $mentorId,string $reason):void {
  Access::manage($actor,$project);$mentor=User::where('role','mentor')->where('active',true)->findOrFail($mentorId);abort_unless($actor->role==='admin'||$mentor->department_id===$actor->department_id,403);
  DB::transaction(function()use($actor,$project,$mentor,$reason){$p=Project::lockForUpdate()->findOrFail($project->id);Assignment::where('project_id',$p->id)->whereNull('ends_at')->update(['ends_at'=>now()]);Assignment::create(['project_id'=>$p->id,'mentor_id'=>$mentor->id,'starts_at'=>now(),'reason'=>$reason]);$p->update(['mentor_id'=>$mentor->id,'department_id'=>$mentor->department_id]);Access::audit('mentor_changed',$p->id,['reason'=>$reason]);$this->activity($p,$actor,'assigned','مسئول پروژه به '.$mentor->name.' تغییر کرد.');app(Notify::class)->event('mentor_assigned',$p,[],"assign:$p->id:".Assignment::max('id'));});
 }
 public function transition(User $actor,Project $project,string $action,string $reason):void {
  Access::project($actor,$project);abort_unless($actor->isStaff(),403);
  DB::transaction(function()use($actor,$project,$action,$reason){$p=Project::lockForUpdate()->findOrFail($project->id);
   if(in_array($action,['pause','resume','cancelled','archived','extra_edit']))Access::manage($actor,$p);
   if($action==='pause'){abort_unless($p->isActive(),422);$p->update(['paused_at'=>now()]);}
   elseif($action==='resume'){$seconds=$p->paused_at?->diffInSeconds(now());abort_unless($seconds>0,422);$p->periods()->where('expires_at','>',$p->paused_at)->get()->each(function($s)use($seconds,$p){$v=['expires_at'=>$s->expires_at->addSeconds($seconds)];if($s->starts_at->gte($p->paused_at))$v['starts_at']=$s->starts_at->addSeconds($seconds);$s->update($v);});$p->update(['expires_at'=>$p->expires_at->addSeconds($seconds),'paused_at'=>null]);}
   elseif($action==='extra_edit'){$p->increment('edits_limit');}
   else{abort_unless($p->status!=='requested'&&(!in_array($p->status,['cancelled','archived'])||$actor->isManager()),422);abort_unless(in_array($action,['in_progress','waiting_customer','ready','delivered','cancelled','archived']),422);$p->update(['status'=>$action]);if($action==='delivered'){$p->update(['delivered_at'=>now()]);app(Reviews::class)->invite($p);app(Notify::class)->event('delivery',$p,['delivery_url'=>url('/projects/'.$p->id),'service_name'=>'سایت شما'],"delivered:$p->id:".($p->currentPeriod()?->id??0));}}
   Access::audit($action,$p->id,['reason'=>$reason]);$this->activity($p,$actor,$action,$reason,false);
  });
 }
}
