unit dm_LocalData;

interface

uses
  System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option,
  FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
  FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.SQLite,
  FireDAC.Phys.SQLiteDef, FireDAC.Stan.ExprFuncs,
  FireDAC.Phys.SQLiteWrapper.Stat, FireDAC.VCLUI.Wait, Data.DB,
  FireDAC.Comp.Client, FireDAC.Comp.UI, FireDAC.Stan.Param, System.IOUtils;

type
  TdmLocalData = class(TDataModule)
    localConn: TFDConnection;
    sqliteDriver: TFDPhysSQLiteDriverLink;
    waitCursor: TFDGUIxWaitCursor;
    procedure DataModuleCreate(Sender: TObject);
  private
    function GetLocalDbPath: string;
    procedure InitDatabaseSchema;
  public
    function NewGuidString: string;
    procedure ExecLocalSQL(const ASQL: string; const AParams: array of Variant);
    function OpenLocalQuery(const ASQL: string): TFDQuery; overload;
    function OpenLocalQuery(const ASQL: string; const AParams: array of Variant): TFDQuery; overload;
  end;

var
  dmLocalData: TdmLocalData;

implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

function TdmLocalData.GetLocalDbPath: string;
begin
  Result := TPath.Combine(ExtractFilePath(ParamStr(0)), 'fabricacion_local.db');
end;

function TdmLocalData.NewGuidString: string;
var
  LGUID: TGUID;
begin
  CreateGUID(LGUID);
  Result := GUIDToString(LGUID);
end;

procedure TdmLocalData.DataModuleCreate(Sender: TObject);
var
  LDbPath: string;
begin
  LDbPath := GetLocalDbPath;
  localConn.Connected := False;
  localConn.Params.Clear;
  localConn.Params.DriverID := 'SQLite';
  localConn.Params.Database := LDbPath;
  localConn.Params.Add('LockingMode=Normal');
  localConn.Params.Add('Synchronous=Normal');
  localConn.Params.Add('BusyTimeout=10000');
  localConn.Connected := True;

  InitDatabaseSchema;
end;

procedure TdmLocalData.InitDatabaseSchema;
const
  SQL_SCHEMA =
    'CREATE TABLE IF NOT EXISTS local_recetas (' +
    '  id_servidor INTEGER PRIMARY KEY, ' +
    '  descripcion TEXT NOT NULL, ' +
    '  version TEXT, ' +
    '  activo INTEGER DEFAULT 1 ' +
    ');' +

    'CREATE TABLE IF NOT EXISTS local_recetas_procesos (' +
    '  id_servidor INTEGER PRIMARY KEY, ' +
    '  receta_id INTEGER NOT NULL, ' +
    '  orden INTEGER DEFAULT 1, ' +
    '  nombre TEXT NOT NULL, ' +
    '  duracion_minutos INTEGER DEFAULT 0, ' +
    '  temperatura REAL DEFAULT 0, ' +
    '  ph REAL DEFAULT 0, ' +
    '  proceso_final INTEGER DEFAULT 0, ' +
    '  id_articulo_resultado INTEGER ' +
    ');' +

    'CREATE TABLE IF NOT EXISTS local_procesos_ingredientes (' +
    '  id_servidor INTEGER PRIMARY KEY, ' +
    '  proceso_id INTEGER NOT NULL, ' +
    '  id_materia_prima INTEGER NOT NULL, ' +
    '  materia_prima_nombre TEXT, ' +
    '  cantidad_base REAL NOT NULL, ' +
    '  unidad TEXT DEFAULT ''g'' ' +
    ');' +

    'CREATE TABLE IF NOT EXISTS local_materias_primas (' +
    '  id_servidor INTEGER PRIMARY KEY, ' +
    '  descripcion TEXT NOT NULL, ' +
    '  codigo_barras TEXT ' +
    ');' +

    'CREATE TABLE IF NOT EXISTS local_lotes_disponibles (' +
    '  id_entrada INTEGER PRIMARY KEY, ' +
    '  id_materia_prima INTEGER NOT NULL, ' +
    '  lote TEXT NOT NULL, ' +
    '  fecha_caducidad TEXT, ' +
    '  stock_restante REAL DEFAULT 0 ' +
    ');' +

    'CREATE TABLE IF NOT EXISTS local_elaboraciones (' +
    '  local_guid TEXT PRIMARY KEY, ' +
    '  server_id INTEGER DEFAULT 0, ' +
    '  id_obrador INTEGER DEFAULT 1, ' +
    '  id_receta INTEGER NOT NULL, ' +
    '  receta_nombre TEXT, ' +
    '  numero_masas INTEGER DEFAULT 1, ' +
    '  multiplicador REAL DEFAULT 1.0, ' +
    '  masa_actual INTEGER DEFAULT 1, ' +
    '  hora_inicio TEXT, ' +
    '  hora_fin TEXT, ' +
    '  temp_obrador REAL, ' +
    '  temp_masa_final REAL, ' +
    '  tiempo_real_minutos INTEGER, ' +
    '  ok_visual INTEGER DEFAULT 1, ' +
    '  observaciones TEXT, ' +
    '  estado TEXT DEFAULT ''PENDIENTE'', ' + // PENDIENTE, EN_PESAJE, EN_AMASADO, FINALIZADA
    '  sync_status TEXT DEFAULT ''PENDING'', ' + // PENDING, SYNCING, SYNCED, ERROR
    '  created_at TEXT NOT NULL ' +
    ');' +

    'CREATE TABLE IF NOT EXISTS local_lotes_consumidos (' +
    '  local_guid TEXT PRIMARY KEY, ' +
    '  elaboracion_guid TEXT NOT NULL, ' +
    '  server_elaboracion_id INTEGER DEFAULT 0, ' +
    '  id_materia_prima INTEGER NOT NULL, ' +
    '  materia_prima_nombre TEXT, ' +
    '  lote_texto TEXT NOT NULL, ' +
    '  lote_entrada_id INTEGER DEFAULT 0, ' +
    '  cantidad REAL NOT NULL, ' +
    '  unidad TEXT DEFAULT ''g'', ' +
    '  masa_numero INTEGER DEFAULT 1, ' +
    '  sync_status TEXT DEFAULT ''PENDING'', ' +
    '  created_at TEXT NOT NULL ' +
    ');' +

    'CREATE TABLE IF NOT EXISTS local_empresas (' +
    '  id_servidor INTEGER PRIMARY KEY, ' +
    '  nombre TEXT NOT NULL ' +
    ');' +

    'CREATE TABLE IF NOT EXISTS local_obradores (' +
    '  id_servidor INTEGER PRIMARY KEY, ' +
    '  id_empresa INTEGER NOT NULL, ' +
    '  nombre TEXT NOT NULL ' +
    ');' +

    'CREATE TABLE IF NOT EXISTS local_sync_log (' +
    '  id INTEGER PRIMARY KEY AUTOINCREMENT, ' +
    '  fecha TEXT NOT NULL, ' +
    '  operacion TEXT NOT NULL, ' +
    '  detalles TEXT, ' +
    '  resultado TEXT ' +
    ');';
begin
  localConn.ExecSQL(SQL_SCHEMA);
end;

procedure TdmLocalData.ExecLocalSQL(const ASQL: string; const AParams: array of Variant);
begin
  localConn.ExecSQL(ASQL, AParams);
end;

function TdmLocalData.OpenLocalQuery(const ASQL: string): TFDQuery;
begin
  Result := TFDQuery.Create(nil);
  Result.Connection := localConn;
  Result.SQL.Text := ASQL;
  Result.Open;
end;

function TdmLocalData.OpenLocalQuery(const ASQL: string; const AParams: array of Variant): TFDQuery;
var
  I: Integer;
begin
  Result := TFDQuery.Create(nil);
  Result.Connection := localConn;
  Result.SQL.Text := ASQL;
  for I := 0 to High(AParams) do
    Result.Params[I].Value := AParams[I];
  Result.Open;
end;

end.
