<?php

namespace App\Services;

use App\Http\Responses\ApiResponse;
use App\Models\ContentModel;
use App\Models\ContentModelField;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class ContentModelFieldService
{
    protected const TYPE_MAP = [
        'varchar' => 'string',
        'text' => 'text',
        'longtext' => 'longText',
        'int' => 'integer',
        'decimal' => 'decimal',
        'date' => 'date',
        'datetime' => 'dateTime',
        'json' => 'json',
    ];

    public function index(int $modelId): array
    {
        $fields = ContentModelField::where('model_id', $modelId)
            ->orderBy('sort', 'asc')
            ->orderBy('id', 'asc')
            ->get();

        return ApiResponse::success($fields);
    }

    public function store(int $modelId, array $data): array
    {
        $model = ContentModel::find($modelId);

        if (! $model) {
            return ApiResponse::error(40201, '模型不存在');
        }

        if (ContentModelField::where('model_id', $modelId)->where('field', $data['field'])->exists()) {
            return ApiResponse::error(40301, '字段名已存在');
        }

        $field = new ContentModelField([
            'model_id' => $modelId,
            'name' => $data['name'],
            'field' => $data['field'],
            'type' => $data['type'] ?? 'varchar',
            'length' => $data['length'] ?? null,
            'decimal_precision' => $data['decimal_precision'] ?? null,
            'default_value' => $data['default_value'] ?? null,
            'form_type' => $data['form_type'] ?? 'text',
            'form_config' => $data['form_config'] ?? null,
            'sort' => $data['sort'] ?? 0,
            'status' => $data['status'] ?? 1,
        ]);

        $this->addColumn($model->table_name, $field);

        return DB::transaction(function () use ($field) {
            $field->save();

            return ApiResponse::success($field, '创建成功');
        });
    }

    public function update(int $id, array $data): array
    {
        $field = ContentModelField::find($id);

        if (! $field) {
            return ApiResponse::error(40301, '字段不存在');
        }

        $updateData = array_filter([
            'name' => $data['name'] ?? null,
            'type' => $data['type'] ?? null,
            'length' => $data['length'] ?? null,
            'decimal_precision' => $data['decimal_precision'] ?? null,
            'default_value' => $data['default_value'] ?? null,
            'form_type' => $data['form_type'] ?? null,
            'form_config' => $data['form_config'] ?? null,
            'sort' => $data['sort'] ?? null,
            'status' => $data['status'] ?? null,
        ], fn ($value) => $value !== null);

        $field->fill($updateData);
        $this->changeColumn($field->model->table_name, $field);

        return DB::transaction(function () use ($field, $updateData) {
            $field->update($updateData);

            return ApiResponse::success($field, '更新成功');
        });
    }

    public function destroy(int $id): array
    {
        $field = ContentModelField::find($id);

        if (! $field) {
            return ApiResponse::error(40301, '字段不存在');
        }

        $tableName = $field->model->table_name;
        $columnName = $field->field;

        $this->dropColumn($tableName, $columnName);

        return DB::transaction(function () use ($field) {
            $field->delete();

            return ApiResponse::success(null, '删除成功');
        });
    }

    public function saveSort(array $ids, array $sorts): array
    {
        foreach ($ids as $index => $id) {
            ContentModelField::where('id', $id)->update([
                'sort' => isset($sorts[$index]) ? intval($sorts[$index]) : 0,
            ]);
        }

        return ApiResponse::success(null, '排序保存成功');
    }

    protected function addColumn(string $tableName, ContentModelField $field): void
    {
        if (! Schema::hasTable($tableName) || Schema::hasColumn($tableName, $field->field)) {
            return;
        }

        try {
            Schema::table($tableName, function ($table) use ($field) {
                $column = $this->buildColumnDefinition($table, $field);
                $column->nullable();

                if ($field->default_value !== null && $field->default_value !== '') {
                    $column->default($field->default_value);
                }
            });
        } catch (\Throwable $e) {
            report($e);
        }
    }

    protected function changeColumn(string $tableName, ContentModelField $field): void
    {
        if (! Schema::hasTable($tableName) || ! Schema::hasColumn($tableName, $field->field)) {
            return;
        }

        $driver = config('database.connections.'.config('database.default').'.driver');

        if ($driver === 'sqlite') {
            return;
        }

        try {
            Schema::table($tableName, function ($table) use ($field) {
                $column = $this->buildColumnDefinition($table, $field);
                $column->nullable();

                if ($field->default_value !== null && $field->default_value !== '') {
                    $column->default($field->default_value);
                }

                $column->change();
            });
        } catch (\Throwable $e) {
            report($e);
        }
    }

    protected function dropColumn(string $tableName, string $columnName): void
    {
        if (! Schema::hasTable($tableName) || ! Schema::hasColumn($tableName, $columnName)) {
            return;
        }

        try {
            Schema::table($tableName, function ($table) use ($columnName) {
                $table->dropColumn($columnName);
            });
        } catch (\Throwable $e) {
            report($e);
        }
    }

    protected function buildColumnDefinition($table, ContentModelField $field)
    {
        $schemaMethod = self::TYPE_MAP[$field->type] ?? 'string';
        $columnName = $field->field;

        return match ($schemaMethod) {
            'string' => $table->string($columnName, $field->length ?? 255),
            'text' => $table->text($columnName),
            'longText' => $table->longText($columnName),
            'integer' => $table->integer($columnName),
            'decimal' => $table->decimal($columnName, $field->length ?? 10, $field->decimal_precision ?? 2),
            'date' => $table->date($columnName),
            'dateTime' => $table->dateTime($columnName),
            'json' => $table->json($columnName),
            default => $table->string($columnName, $field->length ?? 255),
        };
    }
}
