app OpenSaaS {
  wasp: {
    version: "^0.13.2"
  },

  title: "My Open SaaS App",

  head: [
        "<meta property='og:type' content='website' />",
        "<meta property='og:title' content='My Open SaaS App' />",
        "<meta property='og:url' content='https://opensaas.sh' />",
        "<meta property='og:description' content='I made a SaaS App. Buy my stuff.' />",
        "<meta property='og:image' content='https://opensaas.sh/public-banner.png' />",
        "<meta name='twitter:image' content='https://opensaas.sh/public-banner.png' />",
        "<meta name='twitter:image:width' content='800' />",
        "<meta name='twitter:image:height' content='400' />",
        "<meta name='twitter:card' content='summary_large_image' />",
        // TODO: You can put your Plausible analytics scripts below (https://docs.opensaas.sh/guides/analytics/):
        // NOTE: Plausible does not use Cookies, so you can simply add the scripts here.
        // Google, on the other hand, does, so you must instead add the script dynamically
        // via the Cookie Consent component after the user clicks the "Accept" cookies button.
        "<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.js'></script>",  // for production
        "<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.local.js'></script>",  // for development
  ],

  // 🔐 Auth out of the box! https://wasp-lang.dev/docs/auth/overview
  auth: {
    userEntity: User,
    methods: {
      // NOTE: If you decide to not use email auth, make sure to also delete the related routes and pages below.
      //   (RequestPasswordReset(Route|Page), PasswordReset(Route|Page), EmailVerification(Route|Page))
      email: {
        fromField: {
          name: "Open SaaS App",
          email: "me@example.com"
        },
        emailVerification: {
          clientRoute: EmailVerificationRoute,
          getEmailContentFn: import { getVerificationEmailContent } from "@src/server/auth/email",
        },
        passwordReset: {
          clientRoute: PasswordResetRoute,
          getEmailContentFn: import { getPasswordResetEmailContent } from "@src/server/auth/email",
        },
        userSignupFields: import { getEmailUserFields } from "@src/server/auth/userSignupFields",
      },
      // Uncomment to enable Google Auth (check https://wasp-lang.dev/docs/auth/social-auth/google for setup instructions):
      // google: { // Guide for setting up Auth via Google
      //   userSignupFields: import { getGoogleUserFields } from "@src/server/auth/userSignupFields",
      //   configFn: import { getGoogleAuthConfig } from "@src/server/auth/userSignupFields",
      // },
      // Uncomment to enable GitHub Auth (check https://wasp-lang.dev/docs/auth/social-auth/github for setup instructions):
      // gitHub: {
      //   userSignupFields: import { getGitHubUserFields } from "@src/server/auth/userSignupFields",
      //   configFn: import { getGitHubAuthConfig } from "@src/server/auth/userSignupFields",
      // },
    },
    onAuthFailedRedirectTo: "/login",
    onAuthSucceededRedirectTo: "/demo-app",
  },

  db: {
    system: PostgreSQL,
    // Run `wasp db seed` to seed the database with the seed functions below:
    seeds: [
      // Populates the database with a bunch of fake users to work with during development.
      import { devSeedUsers } from "@src/server/scripts/usersSeed.js",
    ]
  },

  client: {
    rootComponent: import App from "@src/client/App",
  },

  emailSender: {
    // NOTE: "Dummy" provider is just for local development purposes.
    //   Make sure to check the server logs for the email confirmation url (it will not be sent to an address)!
    //   Once you are ready for production, switch to e.g. "SendGrid" or "MailGun" providers. Check out https://docs.opensaas.sh/guides/email-sending/ .
    provider: Dummy,
    defaultFrom: {
      name: "Open SaaS App",
      // When using a real provider, e.g. SendGrid, you must use the same email address that you configured your account to send out emails with!
      email: "me@example.com"
    },
  },
}

/* 💽 Wasp defines DB entities via Prisma Database Models:
 * https://wasp-lang.dev/docs/data-model/entities
 */

entity User {=psl
  id                        String          @id @default(uuid())
  createdAt                 DateTime        @default(now())

  email                     String?         @unique
  username                  String?         @unique
  lastActiveTimestamp       DateTime        @default(now())
  isAdmin                   Boolean         @default(false)

  stripeId                  String?
  checkoutSessionId         String?
  subscriptionTier          String?
  subscriptionStatus        String?
  sendEmail                 Boolean         @default(false)
  datePaid                  DateTime?
  credits                   Int             @default(3)

  gptResponses              GptResponse[]
  contactFormMessages       ContactFormMessage[]
  tasks                     Task[]
  files                     File[]
psl=}

entity GptResponse {=psl
  id                        String          @id @default(uuid())
  createdAt                 DateTime        @default(now())
  updatedAt                 DateTime        @updatedAt

  user                      User            @relation(fields: [userId], references: [id])
  userId                    String

  content                   String
psl=}

entity Task {=psl
  id                        String          @id @default(uuid())
  createdAt                 DateTime        @default(now())

  user                      User            @relation(fields: [userId], references: [id])
  userId                    String

  description               String
  time                      String          @default("1")
  isDone                    Boolean         @default(false)
psl=}

entity File {=psl
  id                        String          @id @default(uuid())
  createdAt                 DateTime        @default(now())

  user                      User            @relation(fields: [userId], references: [id])
  userId                    String

  name                      String
  type                      String
  key                       String
  uploadUrl                 String
psl=}

// TODO: add functionality to allow users to send messages to admin
// and make them accessible via the admin dashboard
entity ContactFormMessage {=psl
  id                        String          @id @default(uuid())
  createdAt                 DateTime        @default(now())

  user                      User            @relation(fields: [userId], references: [id])
  userId                    String

  content                   String
  isRead                    Boolean         @default(false)
  repliedAt                 DateTime?
psl=}

entity DailyStats {=psl
  id                               Int             @id @default(autoincrement())
  date                             DateTime        @default(now()) @unique

  totalViews                       Int             @default(0)
  prevDayViewsChangePercent        String          @default("0")
  userCount                        Int             @default(0)
  paidUserCount                    Int             @default(0)
  userDelta                        Int             @default(0)
  paidUserDelta                    Int             @default(0)
  totalRevenue                     Float             @default(0)
  totalProfit                      Float             @default(0)

  sources                          PageViewSource[]
psl=}

entity PageViewSource {=psl
  @@id([date, name])
  name                     String
  date                     DateTime        @default(now())

  dailyStats               DailyStats?     @relation(fields: [dailyStatsId], references: [id])
  dailyStatsId             Int?

  visitors                 Int
psl=}

entity Logs {=psl
  id                       Int             @id @default(autoincrement())
  createdAt                DateTime        @default(now())

  message                  String
  level                    String
psl=}

/* 📡 These are the Wasp client Routes and Pages.
 * You can easily make them inaccessible to the unauthenticated user w/ 'authRequired: true'.
 * https://wasp-lang.dev/docs/tutorial/pages
 */

route LandingPageRoute { path: "/", to: LandingPage }
page LandingPage {
  component: import LandingPage from "@src/client/landing-page/LandingPage"
}

//#region Auth Pages
route LoginRoute { path: "/login", to: LoginPage }
page LoginPage {
  component: import Login from "@src/client/auth/LoginPage"
}

route SignupRoute { path: "/signup", to: SignupPage }
page SignupPage {
  component: import { Signup } from "@src/client/auth/SignupPage"
}

route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordResetPage }
page RequestPasswordResetPage {
  component: import { RequestPasswordReset } from "@src/client/auth/RequestPasswordReset",
}

route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage }
page PasswordResetPage {
  component: import { PasswordReset } from "@src/client/auth/PasswordReset",
}

route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage }
page EmailVerificationPage {
  component: import { EmailVerification } from "@src/client/auth/EmailVerification",
}
//#endregion

route DemoAppRoute { path: "/demo-app", to: DemoAppPage }
page DemoAppPage {
  authRequired: true,
  component: import DemoAppPage from "@src/client/app/DemoAppPage"
}

route PricingPageRoute { path: "/pricing", to: PricingPage }
page PricingPage {
  component: import PricingPage from "@src/client/app/PricingPage"
}

route AccountRoute { path: "/account", to: AccountPage }
page AccountPage {
  authRequired: true,
  component: import Account from "@src/client/app/AccountPage"
}

route CheckoutRoute { path: "/checkout", to: CheckoutPage }
page CheckoutPage {
  authRequired: true,
  component: import Checkout from "@src/client/app/CheckoutPage"
}

route FileUploadRoute { path: "/file-upload", to: FileUploadPage }
page FileUploadPage {
  authRequired: true,
  component: import FileUpload from "@src/client/app/FileUploadPage"
}

//#region Admin Pages
route AdminRoute { path: "/admin", to: DashboardPage }
page DashboardPage {
  authRequired: true,
  component: import Dashboard from "@src/client/admin/pages/DashboardPage"
}

route AdminUsersRoute { path: "/admin/users", to: AdminUsersPage }
page AdminUsersPage {
  authRequired: true,
  component: import AdminUsers from "@src/client/admin/pages/Users"
}

route AdminSettingsRoute { path: "/admin/settings", to: AdminSettingsPage }
page AdminSettingsPage {
  authRequired: true,
  component: import AdminSettings from "@src/client/admin/pages/Settings"
}

route AdminChartsRoute { path: "/admin/chart", to: AdminChartsPage }
page AdminChartsPage {
  authRequired: true,
  component: import AdminCharts from "@src/client/admin/pages/Chart"
}

route AdminMessagesRoute { path: "/admin/messages", to: AdminMessagesPage }
page AdminMessagesPage {
  authRequired: true,
  component: import AdminMessages from "@src/client/admin/pages/Messages"
}

route AdminFormElementsRoute { path: "/admin/forms/form-elements", to: AdminFormElementsPage }
page AdminFormElementsPage {
  authRequired: true,
  component: import AdminForms from "@src/client/admin/pages/Form/FormElements"
}

route AdminFormLayoutsRoute { path: "/admin/forms/form-layouts", to: AdminFormLayoutsPage }
page AdminFormLayoutsPage {
  authRequired: true,
  component: import AdminForms from "@src/client/admin/pages/Form/FormLayout"
}

route AdminCalendarRoute { path: "/admin/calendar", to: AdminCalendarPage }
page AdminCalendarPage {
  authRequired: true,
  component: import AdminCalendar from "@src/client/admin/pages/Calendar"
}

route AdminUIAlertsRoute { path: "/admin/ui/alerts", to: AdminUIAlertsPage }
page AdminUIAlertsPage {
  authRequired: true,
  component: import AdminUI from "@src/client/admin/pages/UiElements/Alerts"
}

route AdminUIButtonsRoute { path: "/admin/ui/buttons", to: AdminUIButtonsPage }
page AdminUIButtonsPage {
  authRequired: true,
  component: import AdminUI from "@src/client/admin/pages/UiElements/Buttons"
}
//#endregion

/* ⛑ These are the Wasp Operations: server code that you can easily call
 * from the client. Queries fetch stuff, Actions modify/do stuff.
 * https://wasp-lang.dev/docs/data-model/operations/overview
 */

// 📝 Actions

action generateGptResponse {
  fn: import { generateGptResponse } from "@src/server/actions.js",
  entities: [User, Task, GptResponse]
}

action createTask {
  fn: import { createTask } from "@src/server/actions.js",
  entities: [Task]
}

action deleteTask {
  fn: import { deleteTask } from "@src/server/actions.js",
  entities: [Task]
}

action updateTask {
  fn: import { updateTask } from "@src/server/actions.js",
  entities: [Task]
}

action stripePayment {
  fn: import { stripePayment } from "@src/server/actions.js",
  entities: [User]
}

action updateCurrentUser {
  fn: import { updateCurrentUser } from "@src/server/actions.js",
  entities: [User]
}

action updateUserById {
  fn: import { updateUserById } from "@src/server/actions.js",
  entities: [User]
}

action createFile {
  fn: import { createFile } from "@src/server/actions.js",
  entities: [User, File]
}


// 📚 Queries

query getGptResponses {
  fn: import { getGptResponses } from "@src/server/queries.js",
  entities: [User, GptResponse]
}

query getAllTasksByUser {
  fn: import { getAllTasksByUser } from "@src/server/queries.js",
  entities: [Task]
}

query getAllFilesByUser {
  fn: import { getAllFilesByUser } from "@src/server/queries.js",
  entities: [User, File]
}

query getDownloadFileSignedURL {
  fn: import { getDownloadFileSignedURL } from "@src/server/queries.js",
  entities: [User, File]
}

query getDailyStats {
  fn: import { getDailyStats } from "@src/server/queries.js",
  entities: [User, DailyStats]
}

query getPaginatedUsers {
  fn: import { getPaginatedUsers } from "@src/server/queries.js",
  entities: [User]
}

/*
 * 📡 These are custom Wasp API Endpoints.
 * Use them for callbacks, webhooks, API for other services to consume, etc.
 * https://wasp-lang.dev/docs/advanced/apis
 */

api stripeWebhook {
  fn: import { stripeWebhook } from "@src/server/webhooks/stripe.js",
  entities: [User],
  middlewareConfigFn: import { stripeMiddlewareFn } from "@src/server/webhooks/stripe.js",
  httpRoute: (POST, "/stripe-webhook")
}

/* 🕵️‍♂️ These are the Wasp Jobs. Use them to set up recurring tasks and/or queues.
 * https://wasp-lang.dev/docs/advanced/jobs
 */

job emailChecker {
  executor: PgBoss,
  perform: {
    fn: import { checkAndQueueEmails } from "@src/server/workers/checkAndQueueEmails.js"
  },
  schedule: {
    cron: "0 7 * * 1" // at 7:00 am every Monday
  },
  entities: [User]
}

job dailyStatsJob {
  executor: PgBoss,
  perform: {
    fn: import { calculateDailyStats } from "@src/server/workers/calculateDailyStats.js"
  },
  schedule: {
    cron: "0 * * * *" // every hour. useful in production
    // cron: "* * * * *" // every minute. useful for debugging
  },
  entities: [User, DailyStats, Logs, PageViewSource]
}
