import rateLimit from 'express-rate-limit';
import RedisStore from 'rate-limit-redis';
import { redis } from '../config/redis';
import { env } from '../config/env';

export const globalRateLimit = rateLimit({
  windowMs: env.RATE_LIMIT_WINDOW_MS,
  max: env.RATE_LIMIT_MAX,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:global:',
  }),
  message: {
    error: {
      message: 'Too many requests, please try again later',
      code: 'RATE_LIMIT_EXCEEDED',
    },
  },
});

export const emailRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 30,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:email:',
  }),
  message: {
    error: {
      message: 'Too many email requests, please try again later',
      code: 'EMAIL_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const responseRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 10,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:response:',
  }),
  message: {
    error: {
      message: 'Too many response submissions, please try again later',
      code: 'RESPONSE_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const shiftSignupRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 10,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:shift-signup:',
  }),
  message: {
    error: {
      message: 'Too many signup attempts, please try again later',
      code: 'SHIFT_SIGNUP_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const canvassVisitRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 30,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:canvass-visit:',
  }),
  message: {
    error: {
      message: 'Too many visit recordings, please slow down',
      code: 'CANVASS_VISIT_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const canvassBulkVisitRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 5, // Stricter limit for bulk operations
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:canvass-visit-bulk:',
  }),
  message: {
    error: {
      message: 'Too many bulk visit recordings, please slow down',
      code: 'CANVASS_BULK_VISIT_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const gpsTrackingRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 6,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:gps-tracking:',
  }),
  message: {
    error: {
      message: 'Too many GPS tracking requests, please slow down',
      code: 'GPS_TRACKING_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const canvassGeocodeRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 10,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:canvass-geocode:',
  }),
  message: {
    error: {
      message: 'Too many geocode requests, please slow down',
      code: 'CANVASS_GEOCODE_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const adTrackingRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 60, // 60 events/min per IP (generous for scroll-heavy gallery pages)
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:ad-track:',
  }),
  message: {
    error: {
      message: 'Too many tracking requests',
      code: 'RATE_LIMIT_EXCEEDED',
    },
  },
});

export const smsSendRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 10,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:sms-send:',
  }),
  message: {
    error: {
      message: 'Too many SMS send requests, please try again later',
      code: 'SMS_SEND_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const quickJoinRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 10,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:quick-join:',
  }),
  message: {
    error: {
      message: 'Too many join attempts, please try again later',
      code: 'QUICK_JOIN_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const paymentCheckoutRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 10, // 10 checkout sessions per hour per IP
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:payment-checkout:',
  }),
  message: {
    error: {
      message: 'Too many payment requests, please try again later',
      code: 'PAYMENT_CHECKOUT_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const authRateLimit = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 15,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:auth:',
  }),
  message: {
    error: {
      message: 'Too many authentication attempts, please try again later',
      code: 'AUTH_RATE_LIMIT_EXCEEDED',
    },
  },
});

// Separate stricter rate limit for login to prevent credential stuffing
// Isolated from the general auth budget so register/refresh/logout don't consume login slots
export const loginRateLimit = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 10,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:login:',
  }),
  message: {
    error: {
      message: 'Too many login attempts, please try again later',
      code: 'LOGIN_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const observabilityRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 20, // 20 requests per minute (stricter than global 500/min)
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:observability:',
  }),
  message: {
    error: {
      message: 'Too many observability requests, please try again later',
      code: 'OBSERVABILITY_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const docsAnalyticsRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 60, // 60 requests/min per IP
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:docs-analytics:',
  }),
  message: {
    error: {
      message: 'Too many tracking requests, please slow down',
      code: 'DOCS_ANALYTICS_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const analyticsAdminRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 30,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:analytics-admin:',
  }),
  message: {
    error: {
      message: 'Too many analytics requests, please try again later',
      code: 'ANALYTICS_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const docsCommentAnonRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 5,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:docs-comment-anon:',
  }),
  message: {
    error: {
      message: 'Too many anonymous comments, please try again later',
      code: 'DOCS_COMMENT_ANON_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const docsCommentAuthRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 30,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:docs-comment-auth:',
  }),
  message: {
    error: {
      message: 'Too many comments, please try again later',
      code: 'DOCS_COMMENT_AUTH_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const docsCommentFetchRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 60,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:docs-comment-fetch:',
  }),
  message: {
    error: {
      message: 'Too many comment fetch requests, please slow down',
      code: 'DOCS_COMMENT_FETCH_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const profileViewRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 60, // 60 requests per minute (shared across profile, photo, activity endpoints)
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:profile-view:',
  }),
  message: {
    error: {
      message: 'Too many profile requests, please try again later',
      code: 'PROFILE_VIEW_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const profileEditRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 20,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:profile-edit:',
  }),
  message: {
    error: {
      message: 'Too many profile edit requests, please try again later',
      code: 'PROFILE_EDIT_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const profilePhotoRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 5,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:profile-photo:',
  }),
  message: {
    error: {
      message: 'Too many photo uploads, please try again later',
      code: 'PROFILE_PHOTO_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const profilePasswordRateLimit = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // Stricter than auth (10/15min) — profile passwords may be simpler
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:profile-password:',
  }),
  message: {
    error: {
      message: 'Too many password attempts, please try again later',
      code: 'PROFILE_PASSWORD_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const eventSubmissionRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 5,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:event-submit:',
  }),
  message: {
    error: {
      message: 'Too many event submissions, please try again later',
      code: 'EVENT_SUBMISSION_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const errorReportRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 5,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:error-report:',
  }),
  message: {
    error: {
      message: 'Too many error reports, please try again later',
      code: 'ERROR_REPORT_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const petitionSignRateLimit = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 5,
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:petition-sign:',
  }),
  message: {
    error: {
      message: 'Too many petition signatures, please try again later',
      code: 'PETITION_SIGN_RATE_LIMIT_EXCEEDED',
    },
  },
});

export const healthMetricsRateLimit = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 30, // 30 requests per minute
  standardHeaders: true,
  legacyHeaders: false,
  store: new RedisStore({
    sendCommand: (command: string, ...args: string[]) => redis.call(command, ...args) as Promise<any>,
    prefix: 'rl:health-metrics:',
  }),
  message: {
    error: {
      message: 'Too many health check requests, please try again later',
      code: 'HEALTH_METRICS_RATE_LIMIT_EXCEEDED',
    },
  },
});
