<?php
declare(strict_types=1);
require __DIR__.'/app/bootstrap.php';require_auth();require __DIR__.'/app/layout.php';
$pdo=db();$companyId=company_id();$userId=(int)user()['id'];
$objectMap=['project'=>['projects','id','company_id'],'purchase_order'=>['purchase_orders','id','company_id'],'sales_invoice'=>['sales_invoices','id','company_id'],'supplier_invoice'=>['supplier_invoices','id','company_id'],'contract'=>['project_contracts','id',null],'receipt_voucher'=>['receipt_vouchers','id','company_id'],'payment_voucher'=>['payment_vouchers','id','company_id']];
if(isset($_GET['download'])){$id=(int)$_GET['download'];$q=$pdo->prepare('SELECT * FROM attachments WHERE id=? AND company_id=? AND deleted_at IS NULL');$q->execute([$id,$companyId]);$a=$q->fetch();if(!$a){http_response_code(404);exit('الملف غير موجود.');}$base=realpath(__DIR__.'/uploads/attachments');$path=realpath(__DIR__.'/'.$a['file_path']);if(!$base||!$path||!str_starts_with($path,$base.DIRECTORY_SEPARATOR)||!is_file($path)){http_response_code(404);exit('تعذر العثور على الملف.');}header('Content-Type: '.$a['mime_type']);header('Content-Length: '.filesize($path));header('Content-Disposition: attachment; filename="'.rawurlencode((string)$a['file_name']).'"');header('X-Content-Type-Options: nosniff');readfile($path);exit;}
if($_SERVER['REQUEST_METHOD']==='POST'){verify_csrf();try{$action=(string)($_POST['action']??'');
 if($action==='upload'){$type=(string)($_POST['object_type']??'project');$objectId=(int)($_POST['object_id']??0);if(!isset($objectMap[$type])||!$objectId)throw new RuntimeException('نوع السجل أو رقمه غير صالح.');[$table,$pk,$companyCol]=$objectMap[$type];if($companyCol){$valid=(int)scalar("SELECT COUNT(*) FROM $table WHERE $pk=? AND $companyCol=?",[$objectId,$companyId]);}elseif($type==='contract'){$valid=(int)scalar('SELECT COUNT(*) FROM project_contracts pc JOIN projects p ON p.id=pc.project_id WHERE pc.id=? AND p.company_id=?',[$objectId,$companyId]);}else $valid=0;if(!$valid)throw new RuntimeException('السجل المراد ربط الملف به غير موجود.');if(!isset($_FILES['document'])||($_FILES['document']['error']??UPLOAD_ERR_NO_FILE)!==UPLOAD_ERR_OK)throw new RuntimeException('اختر ملفًا صالحًا.');$file=$_FILES['document'];$size=(int)$file['size'];if($size<=0||$size>10485760)throw new RuntimeException('حجم الملف يجب ألا يتجاوز 10MB.');$original=basename((string)$file['name']);$ext=strtolower(pathinfo($original,PATHINFO_EXTENSION));$allowed=['pdf'=>'application/pdf','png'=>'image/png','jpg'=>'image/jpeg','jpeg'=>'image/jpeg','docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document','xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet','csv'=>'text/plain','zip'=>'application/zip'];if(!isset($allowed[$ext]))throw new RuntimeException('نوع الملف غير مسموح.');$finfo=new finfo(FILEINFO_MIME_TYPE);$mime=(string)$finfo->file((string)$file['tmp_name']);if(in_array($ext,['pdf','png','jpg','jpeg'],true)&&$mime!==$allowed[$ext])throw new RuntimeException('محتوى الملف لا يطابق امتداده.');$dir=__DIR__.'/uploads/attachments';if(!is_dir($dir)&&!mkdir($dir,0750,true))throw new RuntimeException('تعذر إنشاء مجلد المرفقات.');$stored=bin2hex(random_bytes(20)).'.'.$ext;$target=$dir.'/'.$stored;if(!move_uploaded_file((string)$file['tmp_name'],$target))throw new RuntimeException('تعذر حفظ الملف على الخادم.');$hash=hash_file('sha256',$target);$version=(int)scalar('SELECT COALESCE(MAX(version_no),0)+1 FROM attachments WHERE company_id=? AND object_type=? AND object_id=? AND file_name=?',[$companyId,$type,$objectId,$original]);try{$s=$pdo->prepare('INSERT INTO attachments(company_id,object_type,object_id,document_category,file_name,stored_name,file_path,mime_type,file_size,file_hash,version_no,is_confidential,uploaded_by,uploaded_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())');$s->execute([$companyId,$type,$objectId,trim((string)($_POST['document_category']??''))?:null,$original,$stored,'uploads/attachments/'.$stored,$mime,$size,$hash,$version,isset($_POST['is_confidential'])?1:0,$userId]);}catch(Throwable $e){@unlink($target);throw $e;}audit('attachment.upload','attachment',(string)$pdo->lastInsertId(),['object_type'=>$type,'object_id'=>$objectId]);flash('success','تم رفع الملف وأرشفته بالإصدار '.$version.'.');
 }elseif($action==='delete'){$id=(int)($_POST['id']??0);$s=$pdo->prepare('UPDATE attachments SET deleted_at=NOW() WHERE id=? AND company_id=? AND deleted_at IS NULL');$s->execute([$id,$companyId]);if(!$s->rowCount())throw new RuntimeException('تعذر حذف المرفق.');audit('attachment.delete','attachment',(string)$id);flash('success','تم نقل المرفق إلى الأرشيف المحذوف.');
 }}catch(Throwable $e){flash('error',$e instanceof PDOException?'تعذر حفظ المرفق أو توجد نسخة مطابقة.':$e->getMessage());}redirect('documents.php');}
$projects=$pdo->prepare("SELECT id,CONCAT(project_no,' — ',name_ar) label FROM projects WHERE company_id=? AND deleted_at IS NULL ORDER BY project_no");$projects->execute([$companyId]);$projects=$projects->fetchAll();$orders=$pdo->prepare("SELECT id,po_no label FROM purchase_orders WHERE company_id=? ORDER BY id DESC LIMIT 200");$orders->execute([$companyId]);$orders=$orders->fetchAll();$sales=$pdo->prepare("SELECT id,invoice_no label FROM sales_invoices WHERE company_id=? ORDER BY id DESC LIMIT 200");$sales->execute([$companyId]);$sales=$sales->fetchAll();$supplierInvoices=$pdo->prepare("SELECT id,CONCAT(internal_no,' / ',invoice_no) label FROM supplier_invoices WHERE company_id=? ORDER BY id DESC LIMIT 200");$supplierInvoices->execute([$companyId]);$supplierInvoices=$supplierInvoices->fetchAll();$contracts=$pdo->prepare("SELECT pc.id,CONCAT(p.project_no,' — ',pc.contract_no) label FROM project_contracts pc JOIN projects p ON p.id=pc.project_id WHERE p.company_id=? ORDER BY pc.id DESC");$contracts->execute([$companyId]);$contracts=$contracts->fetchAll();$receipts=$pdo->prepare("SELECT id,receipt_no label FROM receipt_vouchers WHERE company_id=? ORDER BY id DESC LIMIT 200");$receipts->execute([$companyId]);$receipts=$receipts->fetchAll();$payments=$pdo->prepare("SELECT id,payment_no label FROM payment_vouchers WHERE company_id=? ORDER BY id DESC LIMIT 200");$payments->execute([$companyId]);$payments=$payments->fetchAll();$objectOptions=['project'=>['مشروع',$projects],'purchase_order'=>['أمر شراء',$orders],'sales_invoice'=>['فاتورة عميل',$sales],'supplier_invoice'=>['فاتورة مورد',$supplierInvoices],'contract'=>['عقد',$contracts],'receipt_voucher'=>['سند قبض',$receipts],'payment_voucher'=>['سند صرف',$payments]];$attachments=$pdo->prepare("SELECT a.*,u.full_name FROM attachments a JOIN users u ON u.id=a.uploaded_by WHERE a.company_id=? AND a.deleted_at IS NULL ORDER BY a.id DESC LIMIT 300");$attachments->execute([$companyId]);$attachments=$attachments->fetchAll();
render_header('documents','المرفقات والأرشفة','حفظ مستندات المشاريع والعقود والفواتير والسندات بإصدارات مؤمنة.');?>
<details class="panel quick-add" open><summary>＋ رفع مرفق</summary><form method="post" enctype="multipart/form-data"><?= csrf_field() ?><input type="hidden" name="action" value="upload"><div class="form-grid"><label>نوع السجل<select name="object_type" id="objectType"><?php foreach($objectOptions as $key=>[$label]):?><option value="<?= e($key) ?>"><?= e($label) ?></option><?php endforeach;?></select></label><label>السجل<select name="object_id" id="objectId" required></select></label><label>تصنيف المستند<select name="document_category"><option value="contract">عقد</option><option value="invoice">فاتورة</option><option value="voucher">سند</option><option value="drawing">مخطط</option><option value="correspondence">مراسلات</option><option value="approval">اعتماد</option><option value="other">أخرى</option></select></label><label>الملف<input type="file" name="document" accept=".pdf,.png,.jpg,.jpeg,.docx,.xlsx,.csv,.zip" required></label><label class="checks"><span><input type="checkbox" name="is_confidential"> ملف سري</span></label></div><button class="primary-btn">رفع وأرشفة</button></form></details>
<section class="panel data-card"><header><h2>سجل المرفقات</h2></header><div class="responsive-table"><table><thead><tr><th>الملف</th><th>الارتباط</th><th>التصنيف</th><th>الإصدار</th><th>الحجم</th><th>الرافع</th><th>التاريخ</th><th></th></tr></thead><tbody><?php foreach($attachments as $a):?><tr><td><?= e($a['file_name']) ?><?= $a['is_confidential']?' 🔒':'' ?></td><td><?= e($a['object_type'].' #'.$a['object_id']) ?></td><td><?= e($a['document_category']?:'—') ?></td><td><?= (int)$a['version_no'] ?></td><td><?= number_format((int)$a['file_size']/1024,1) ?> KB</td><td><?= e($a['full_name']) ?></td><td><?= e($a['uploaded_at']) ?></td><td><a href="?download=<?= (int)$a['id'] ?>">تنزيل</a><form method="post" onsubmit="return confirm('نقل المرفق إلى المحذوفات؟')"><?= csrf_field() ?><input type="hidden" name="action" value="delete"><input type="hidden" name="id" value="<?= (int)$a['id'] ?>"><button>حذف</button></form></td></tr><?php endforeach;?></tbody></table></div></section>
<script>const objects=<?= json_encode(array_map(fn($x)=>$x[1],$objectOptions),JSON_UNESCAPED_UNICODE|JSON_HEX_TAG|JSON_HEX_AMP) ?>;function fillObjects(){objectId.innerHTML='';(objects[objectType.value]||[]).forEach(x=>{const o=document.createElement('option');o.value=x.id;o.textContent=x.label;objectId.append(o)})}objectType.onchange=fillObjects;fillObjects();</script>
<?php render_footer();
