// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// @dart = 2.9

import "dart:collection";
import "dart:ffi";

import "package:ffi/ffi.dart";

import "bindings/bindings.dart";

import "bindings/types.dart" as types;
import "bindings/types.dart" hide Database;

import "bindings/constants.dart";
import "collections/closable_iterator.dart";

/// [Database] represents an open connection to a SQLite database.
///
/// All functions against a database may throw [SQLiteError].
///
/// This database interacts with SQLite synchonously.
class Database {
  DatabaseResource _database;
  bool _open = false;

  /// Open a database located at the file [path].
  Database(String path,
      [int flags = Flags.SQLITE_OPEN_READWRITE | Flags.SQLITE_OPEN_CREATE]) {
    Pointer<Pointer<types.Database>> dbOut = calloc();
    final pathC = Utf8Resource(path.toNativeUtf8());
    final int resultCode =
        bindings.sqlite3_open_v2(pathC.unsafe(), dbOut, flags, nullptr);
    _database = DatabaseResource(dbOut.value);
    calloc.free(dbOut);
    pathC.free();

    if (resultCode == Errors.SQLITE_OK) {
      _open = true;
    } else {
      // Even if "open" fails, sqlite3 will still create a database object. We
      // can just destroy it.
      SQLiteException exception = _loadError(resultCode);
      close();
      throw exception;
    }
  }

  /// Close the database.
  ///
  /// This should only be called once on a database unless an exception is
  /// thrown. It should be called at least once to finalize the database and
  /// avoid resource leaks.
  void close() {
    assert(_open);
    final int resultCode = _database.close();
    if (resultCode == Errors.SQLITE_OK) {
      _open = false;
    } else {
      throw _loadError(resultCode);
    }
  }

  /// Execute a query, discarding any returned rows.
  void execute(String query) {
    Pointer<Pointer<Statement>> statementOut = malloc();
    final queryC = Utf8Resource(query.toNativeUtf8());
    int resultCode = _database.prepare(queryC, -1, statementOut, nullptr);
    final statement = StatementResource(statementOut.value);
    calloc.free(statementOut);
    queryC.free();

    while (resultCode == Errors.SQLITE_ROW || resultCode == Errors.SQLITE_OK) {
      resultCode = statement.step();
    }
    statement.finalize();
    if (resultCode != Errors.SQLITE_DONE) {
      throw _loadError(resultCode);
    }
  }

  /// Evaluate a query and return the resulting rows as an iterable.
  Result query(String query) {
    Pointer<Pointer<Statement>> statementOut = malloc();
    final queryC = Utf8Resource(query.toNativeUtf8());
    int resultCode = _database.prepare(queryC, -1, statementOut, nullptr);
    final statement = StatementResource(statementOut.value);
    calloc.free(statementOut);
    queryC.free();

    if (resultCode != Errors.SQLITE_OK) {
      statement.finalize();
      throw _loadError(resultCode);
    }

    Map<String, int> columnIndices = {};
    int columnCount = statement.columnCount;
    for (int i = 0; i < columnCount; i++) {
      String columnName = statement.columnName(i);
      columnIndices[columnName] = i;
    }

    return Result._(this, statement, columnIndices);
  }

  SQLiteException _loadError([int errorCode]) {
    String errorMessage = _database.errmsg().toDartString();
    if (errorCode == null) {
      return SQLiteException(errorMessage);
    }
    String errorCodeExplanation =
        bindings.sqlite3_errstr(errorCode).toDartString();
    return SQLiteException(
        "$errorMessage (Code $errorCode: $errorCodeExplanation)");
  }
}

/// [Result] represents a [Database.query]'s result and provides an [Iterable]
/// interface for the results to be consumed.
///
/// Please note that this iterator should be [close]d manually if not all [Row]s
/// are consumed.
class Result extends IterableBase<Row> implements ClosableIterable<Row> {
  final ClosableIterator<Row> _iterator;

  Result._(
    Database database,
    StatementResource statement,
    Map<String, int> columnIndices,
  ) : _iterator = _ResultIterator(statement, columnIndices) {}

  void close() => _iterator.close();

  ClosableIterator<Row> get iterator => _iterator;
}

class _ResultIterator implements ClosableIterator<Row> {
  final StatementResource _statement;
  final Map<String, int> _columnIndices;

  Row _currentRow;
  bool _closed = false;

  _ResultIterator(this._statement, this._columnIndices) {}

  bool moveNext() {
    if (_closed) {
      throw SQLiteException("The result has already been closed.");
    }
    if (_currentRow != null) {
      _currentRow._setNotCurrent();
    }
    int stepResult = _statement.step();
    if (stepResult == Errors.SQLITE_ROW) {
      _currentRow = Row._(_statement, _columnIndices);
      return true;
    } else {
      close();
      return false;
    }
  }

  Row get current {
    if (_closed) {
      throw SQLiteException("The result has already been closed.");
    }
    return _currentRow;
  }

  void close() {
    _currentRow._setNotCurrent();
    _closed = true;
    _statement.finalize();
  }
}

class Row {
  final StatementResource _statement;
  final Map<String, int> _columnIndices;

  bool _isCurrentRow = true;

  Row._(this._statement, this._columnIndices) {}

  /// Reads column [columnName].
  ///
  /// By default it returns a dynamically typed value. If [convert] is set to
  /// [Convert.StaticType] the value is converted to the static type computed
  /// for the column by the query compiler.
  dynamic readColumn(String columnName,
      {Convert convert = Convert.DynamicType}) {
    return readColumnByIndex(_columnIndices[columnName], convert: convert);
  }

  /// Reads column [columnName].
  ///
  /// By default it returns a dynamically typed value. If [convert] is set to
  /// [Convert.StaticType] the value is converted to the static type computed
  /// for the column by the query compiler.
  dynamic readColumnByIndex(int columnIndex,
      {Convert convert = Convert.DynamicType}) {
    _checkIsCurrentRow();

    Type dynamicType;
    if (convert == Convert.DynamicType) {
      dynamicType = _typeFromCode(_statement.columnType(columnIndex));
    } else {
      dynamicType =
          _typeFromText(_statement.columnDecltype(columnIndex).toDartString());
    }

    switch (dynamicType) {
      case Type.Integer:
        return readColumnByIndexAsInt(columnIndex);
      case Type.Text:
        return readColumnByIndexAsText(columnIndex);
      case Type.Null:
        return null;
      default:
    }
  }

  /// Reads column [columnName] and converts to [Type.Integer] if not an
  /// integer.
  int readColumnAsInt(String columnName) {
    return readColumnByIndexAsInt(_columnIndices[columnName]);
  }

  /// Reads column [columnIndex] and converts to [Type.Integer] if not an
  /// integer.
  int readColumnByIndexAsInt(int columnIndex) {
    _checkIsCurrentRow();
    return _statement.columnInt(columnIndex);
  }

  /// Reads column [columnName] and converts to [Type.Text] if not text.
  String readColumnAsText(String columnName) {
    return readColumnByIndexAsText(_columnIndices[columnName]);
  }

  /// Reads column [columnIndex] and converts to [Type.Text] if not text.
  String readColumnByIndexAsText(int columnIndex) {
    _checkIsCurrentRow();
    return _statement.columnText(columnIndex).toDartString();
  }

  void _checkIsCurrentRow() {
    if (!_isCurrentRow) {
      throw Exception(
          "This row is not the current row, reading data from the non-current"
          " row is not supported by sqlite.");
    }
  }

  void _setNotCurrent() {
    _isCurrentRow = false;
  }
}

class DatabaseResource implements Finalizable {
  static final NativeFinalizer _finalizer =
      NativeFinalizer(bindings.sqlite3_close_v2_native_return_void.cast());

  /// [_statement] must never escape [StatementResource], otherwise the
  /// [_finalizer] will run prematurely.
  Pointer<types.Database> _database;

  DatabaseResource(this._database) {
    _finalizer.attach(this, _database.cast(), detach: this);
  }

  int close() {
    _finalizer.detach(this);
    return bindings.sqlite3_close_v2(_database);
  }

  int prepare(Utf8Resource query, int nbytes,
      Pointer<Pointer<Statement>> statementOut, Pointer<Pointer<Utf8>> tail) {
    int result = bindings.sqlite3_prepare_v2(
        _database, query.unsafe(), nbytes, statementOut, tail);
    return result;
  }

  Pointer<Utf8> errmsg() => bindings.sqlite3_errmsg(_database);
}

class StatementResource implements Finalizable {
  static final NativeFinalizer _finalizer =
      NativeFinalizer(bindings.sqlite3_finalize_native_return_void.cast());

  /// [_statement] must never escape [StatementResource], otherwise the
  /// [_finalizer] will run prematurely.
  final Pointer<Statement> _statement;

  StatementResource(this._statement) {
    _finalizer.attach(this, _statement.cast(), detach: this);
  }

  int finalize() {
    _finalizer.detach(this);
    return bindings.sqlite3_finalize(_statement);
  }

  int get columnCount => bindings.sqlite3_column_count(_statement);

  String columnName(int index) =>
      bindings.sqlite3_column_name(_statement, index).toDartString();

  int step() => bindings.sqlite3_step(_statement);

  int columnType(int columnIndex) =>
      bindings.sqlite3_column_type(_statement, columnIndex);

  Pointer<Utf8> columnDecltype(int columnIndex) =>
      bindings.sqlite3_column_decltype(_statement, columnIndex);

  int columnInt(int columnIndex) =>
      bindings.sqlite3_column_int(_statement, columnIndex);

  Pointer<Utf8> columnText(int columnIndex) =>
      bindings.sqlite3_column_text(_statement, columnIndex);
}

class Utf8Resource implements Finalizable {
  static final NativeFinalizer _finalizer = NativeFinalizer(posixFree);

  /// [_cString] must never escape [Utf8Resource], otherwise the
  /// [_finalizer] will run prematurely.
  final Pointer<Utf8> _cString;

  Utf8Resource(this._cString) {
    _finalizer.attach(this, _cString.cast(), detach: this);
  }

  void free() {
    _finalizer.detach(this);
    calloc.free(_cString);
  }

  /// Ensure this [Utf8Resource] stays in scope longer than the inner resource.
  Pointer<Utf8> unsafe() => _cString;
}

final DynamicLibrary stdlib = DynamicLibrary.process();
final posixFree = stdlib.lookup<NativeFunction<Void Function(Pointer)>>("free");

Type _typeFromCode(int code) {
  switch (code) {
    case Types.SQLITE_INTEGER:
      return Type.Integer;
    case Types.SQLITE_FLOAT:
      return Type.Float;
    case Types.SQLITE_TEXT:
      return Type.Text;
    case Types.SQLITE_BLOB:
      return Type.Blob;
    case Types.SQLITE_NULL:
      return Type.Null;
  }
  throw Exception("Unknown type [$code]");
}

Type _typeFromText(String textRepresentation) {
  switch (textRepresentation) {
    case "integer":
      return Type.Integer;
    case "float":
      return Type.Float;
    case "text":
      return Type.Text;
    case "blob":
      return Type.Blob;
    case "null":
      return Type.Null;
  }
  throw Exception("Unknown type [$textRepresentation]");
}

enum Type { Integer, Float, Text, Blob, Null }

enum Convert { DynamicType, StaticType }

class SQLiteException {
  final String message;
  SQLiteException(this.message);

  String toString() => message;
}
