<?php

namespace App\Http\Controllers\Home;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Log;

use App\Mail\ContactNotifyMail;

class Contact {
  private $field;

  public function __construct () {
    $this->field = [
      'kenmei' => '',
      'adr' => '',
      'cat' => '',
      'cats' => [
        '' => '',
        'bugreport' => 'バグ報告したい',
        'chat' => 'チャットサービス（XMPP、IRC、Mumble）について聞きたい',
        'social' => 'SNSサービス（Pleroma、PeerTube）について聞きたい',
        'privfront' => '代替SNSフロントサービス（Nitter、Invidious、Librarian、Searx）について聞きたい',
        'storage' => 'ストレージサービス（Gitea、Nextcloud）について聞きたい',
        'otherserv' => '076外サービス（テク諏訪、076萌、URLoli、some.very.questionable.website、hozon.site、xmr.jp等）について聞きたい',
        'scam1' => 'DMCA報告したい',
        'scam2' => '営業したい',
        'scam3' => '法律について',
        'scam4' => '税金について',
        'scam5' => '無駄な話',
      ],
      'bunsyo' => '',
      'gpg' => '',
      'ruleapply' => false,
    ];
  }

  public function index (Request $r) {
    if (isset($r->submit)) return $this->send($r);
    return view('pages.site.contact', ['field' => $this->field, 'err' => []]);
  }

  public function seiko () {
    return view('pages.site.contact-seiko', ['field' => $this->field, 'suc' => ['メールを送りました！', '送信者様は連絡ルールを守ったら、24時間以内で返事します。']]);
  }

  public function send (Request $r) {
    $this->field['adr'] = $r->adr;
    $this->field['kenmei'] = $r->kenmei;
    $this->field['cat'] = $r->cat;
    $this->field['gpg'] = !isset($r->gpg) || is_null($r->gpg) || $r->gpg == '' ? null : file_get_contents($r->file('gpg'));
    $this->field['bunsyo'] = $r->bunsyo;
    $this->field['ruleapply'] = isset($r->ruleapply);

    $err = [];
    $gpg = null;

    // メールアドレス
    if (!isset($this->field['adr']) || is_null($this->field['adr']) || $this->field['adr'] == '') $err[] = 'メールアドレスをご入力下さい。';
    else if (!filter_var($this->field['adr'], FILTER_VALIDATE_EMAIL)) $err[] = 'メールアドレスを正しくご入力下さい。';
    $filename = trim($this->field['adr']).'.key';

    // 件名
    if (!isset($this->field['kenmei']) || is_null($this->field['kenmei']) || $this->field['kenmei'] == '') $err[] = '件名をご入力下さい。';
    if (str_contains($this->field['kenmei'], 'http://') || str_contains($this->field['kenmei'], 'https://')) $err[] = '件名でURLを入らないで下さい。';
    $this->field['bunsyo'] = trim($this->field['bunsyo']);

    // カテゴリ
    if (!isset($this->field['cat']) || is_null($this->field['cat']) || $this->field['cat'] == '') $err[] = 'カテゴリをご選択下さい。';

    // GPG
    if (!isset($this->field['gpg']) || is_null($this->field['gpg']) || $this->field['gpg'] == '') $err[] = 'GPGをご選択下さい。';
    else {
      $gpg = new \gnupg();
      $info = $gpg->import($this->field['gpg']);
      $gpg->addencryptkey($info['fingerprint']);
      Storage::disk('public')->put($filename, $this->field['gpg']);
      $path = Storage::disk('public')->path($filename);
      $verifygpg = explode("\n", $this->run('gpg --dry-run --import '.$path))[0];
      if (!str_contains($verifygpg, '処理数の合計: 1')) $err[] = $verifygpg;
    }

    // 文章
    if (!isset($this->field['bunsyo']) || is_null($this->field['bunsyo']) || $this->field['bunsyo'] == '') $err[] = '文章をご入力下さい。';
    if (str_contains($this->field['bunsyo'], 'http://') || str_contains($this->field['bunsyo'], 'https://')) $err[] = '文章でURLを入らないで下さい。';
    $this->field['bunsyo'] = $gpg->encrypt(trim($this->field['bunsyo']));

    // 連絡ルール
    if (!$this->field['ruleapply']) $err[] = 'ルールを同意して下さい。';

    if (!empty($err)) {
      if (isset($this->field['gpg']) && !is_null($this->field['gpg']) && $this->field['gpg'] != '') Storage::disk('public')->delete($filename);
      return view('pages.site.contact', ['field' => $this->field, 'err' => $err]);
    }

    // カテゴリはDMCA報告、営業、税金、法律、又は無駄な話を選択したら、いつでも送信せず失敗します。
    if (str_contains($this->field['cat'], 'scam')) {
      Storage::disk('public')->delete($filename);
      return view('pages.site.contact', ['field' => $this->field, 'err' => ['送信に失敗しました。数時間後もう一回送信してみて下さい。']]);
    }

    // メールを送る
    try {
      Mail::to(config('mail.from.address'))->send(new ContactNotifyMail($this->field, $filename));
    } catch (\Throwable $e) {
      Storage::disk('public')->delete($filename);
      Log::critical($e);
      return view('pages.site.contact', ['field' => $this->field, 'err' => ['送信に失敗しました。数時間後もう一回送信してみて下さい。']]);
    }

    Storage::disk('public')->delete($filename);
    $this->field['kenmei'] = '';
    $this->field['adr'] = '';
    $this->field['cat'] = '';
    $this->field['bunsyo'] = '';
    $this->field['gpg'] = '';
    $this->field['ruleapply'] = false;

    return redirect('/contact/seiko');
  }

  function run ($bin, $command = '', $force = true) {
    $stream = null;
    $bin .= $force ? ' 2>&1' : '';

    $descriptorSpec = array(
      0 => array('pipe', 'r'),
      1 => array('pipe', 'w')
    );

    $process = proc_open($bin, $descriptorSpec, $pipes);

    if (is_resource($process)) {
      fwrite($pipes[0], $command);
      fclose($pipes[0]);

      $stream = stream_get_contents($pipes[1]);
      fclose($pipes[1]);

      proc_close($process);
    }

    return $stream;
  }
}