<?php

namespace App\Core;

use App\Models\Export\Export;
use Illuminate\Support\Carbon;
use Dipper\Excel\Events\AfterStore;
use Dipper\Excel\Concerns\WithTitle;
use Dipper\Excel\Events\AfterExport;
use Dipper\Excel\Concerns\Exportable;
use Dipper\Excel\Concerns\WithEvents;
use Dipper\Excel\Events\BeforeExport;
use Dipper\Excel\Events\BeforeWriting;
use App\Exceptions\NotAllowedException;
use Illuminate\Support\Facades\Storage;
use Dipper\Excel\Concerns\ShouldAutoSize;
use App\Domains\Export\Repositories\ExportRepository;

abstract class AbstractExport implements WithEvents, WithTitle, ShouldAutoSize
{
    use Exportable;

    public static $classes = [
        \App\Domains\Virtual\Exports\CardExport::class => '客户列表',
        \App\Domains\Virtual\Exports\FlowPoolExport::class => '流量池列表',
        \App\Domains\Virtual\Exports\FlowPoolExportDetailExport::class => '流量池明细',
        \App\Domains\Virtual\Exports\OrderCardExport::class => '订单卡清单',
        \App\Domains\Virtual\Exports\OrderExport::class => '订单导出',
        \App\Domains\Virtual\Exports\PropertyExport::class => '属性导出',
        \App\Domains\Stats\Exports\CompanyCountExport::class => '企业统计',
        \App\Domains\Stats\Exports\OrderExport::class => '订单统计',
        \App\Domains\Stats\Exports\OrderDetailExport::class => '订单明细',
        \App\Domains\Stats\Exports\CompanyReportExport::class => '月报表',
        \App\Domains\Stats\Exports\CompanyReportDetailExport::class => '月报表明细',
    ];

    public $sn;

    public $tag;

    public $filename;

    public function __construct()
    {
        $this->sn = $this->sn();
        $this->tag = $this->tag();
        $this->filename = $this->filename();
        set_time_limit(-1);
        ini_set('memory_limit', '4096m');
    }

    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            BeforeExport::class => [self::class, 'beforeExport'],
            BeforeWriting::class => [self::class, 'beforeWriting'],
            AfterExport::class => [self::class, 'afterExport'],
            AfterStore::class => [self::class, 'afterStore'],
        ];
    }

    /**
     * 开始导出
     *
     * @param BeforeExport $event
     * @return void
     */
    public static function beforeExport(BeforeExport $event)
    {
        $data = [
            'sn' => $event->getConcernable()->sn,
            'tag' => $event->getConcernable()->tag,
            'filename' => $event->getConcernable()->filename,
            'filesize' => 0,
            'conditions' => $event->getConcernable()->conditions ?: null,
            'status' => 0,
            'progress' => 0,
        ];

        Export::create($data);

        app(ExportRepository::class)->forgetCached();
    }

    /**
     * 写入数据
     *
     * @param BeforeWriting $event
     * @return void
     */
    public static function beforeWriting(BeforeWriting $event)
    {
        Export::where(['sn' => $event->getConcernable()->sn])->update([
            'status' => 1,
            'progress' => 50,
        ]);

        app(ExportRepository::class)->forgetCached();
    }

    /**
     * 写入结束
     *
     * @param AfterExport $event
     * @return void
     */
    public static function afterExport(AfterExport $event)
    {
        Export::where(['sn' => $event->getConcernable()->sn])->update([
            'status' => 2,
            'progress' => 90,
        ]);

        app(ExportRepository::class)->forgetCached();
    }

    /**
     * 保存结束
     *
     * @param AfterStore $event
     * @return void
     */
    public static function afterStore(AfterStore $event)
    {
        $disk = Storage::disk($event->getDisk());

        if ($disk->exists($event->getFilePath())) {
            Export::where(['sn' => $event->getConcernable()->sn])->update([
                'filesize' => $disk->size($event->getFilePath()),
                'status' => 3,
                'progress' => 100,
                'disk' => $event->getDisk(),
            ]);
        } else {
            Export::where(['sn' => $event->getConcernable()->sn])->update([
                'status' => 4,
                'progress' => 100,
            ]);
        }

        app(ExportRepository::class)->forgetCached();
    }

    /**
     * 表格标题
     *
     * @return string
     */
    public function title(): string
    {
        $title = $this->tag();

        if (($conditions = $this->conditions) && $conditions['starttime'] && $conditions['endtime']) {
            $title .= Carbon::parse($conditions['starttime'])->format('Ymd') . '-' . Carbon::parse($conditions['endtime'])->format('Ymd');
        }

        if (($conditions = $this->conditions) && $conditions['month']) {
            $title .= Carbon::parse($conditions['month'])->format('Ym');
        }

        return $title ?? '列表';
    }

    /**
     * 序列号
     *
     * @return string
     */
    protected function sn(): string
    {
        return date('YmdHis') .sprintf('%04d', explode('.', microtime(true))[1]) . sprintf('%02d', rand(0, 99));
    }

    /**
     * 文件名称
     *
     * @return string
     */
    protected function filename(): string
    {
        $title = $this->tag();

        $filename = $title . date('YmdHis');

        return "export/{$filename}.xlsx";
    }

    /**
     * 类型
     *
     * @return void
     */
    protected function tag()
    {
        if (!$tag = self::$classes[get_class($this)]) {
            throw new NotAllowedException('类型不允许');
        }

        return $tag;
    }
}
