-- Data model
DROP TABLE reviews;
DROP TABLE reviewers;
DROP TABLE restaurants;
CREATE TABLE restaurants (
  id SERIAL UNIQUE NOT NULL,
  restaurant_name TEXT NOT NULL,
  short_name TEXT NOT NULL UNIQUE,
  PRIMARY KEY (id)
);

CREATE TABLE reviewers (
  id SERIAL UNIQUE NOT NULL,
  reviewer_name TEXT UNIQUE NOT NULL,
  created_date TIMESTAMP,
  last_seen TIMESTAMP,
  PRIMARY KEY (id)
);

CREATE TABLE reviews (
  id SERIAL UNIQUE NOT NULL,
  reviewer_id INTEGER REFERENCES reviewers (id) NOT NULL,
  restaurant_id INTEGER REFERENCES restaurants (id) NOT NULL,
  review_posted TIMESTAMP DEFAULT current_timestamp,
  review TEXT NOT NULL,
  UNIQUE (reviewer_id, restaurant_id),
  PRIMARY KEY (id)
);

-- Stored Procedures

CREATE OR REPLACE FUNCTION get_reviews(sn text)
  RETURNS TABLE(review text, reviewer text)  AS $$
BEGIN
  RETURN QUERY SELECT reviews.review, reviewers.reviewer_name
                FROM reviews
                  INNER JOIN reviewers ON reviews.reviewer_id=reviewers.id
                  INNER JOIN restaurants ON reviews.restaurant_id=restaurants.id
                  WHERE restaurants.short_name=sn
                  ORDER BY review_posted DESC,
                           reviewer_name ASC;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION put_review(sn text, rn text, review text)
  RETURNS VOID AS $$
DECLARE
  restaurant_id int;
  reviewer_id int;
  nowstamp timestamp;
BEGIN
  SELECT restaurants.id INTO restaurant_id FROM restaurants WHERE restaurants.short_name=sn;
  SELECT reviewers.id INTO reviewer_id FROM reviewers WHERE reviewers.reviewer_name=rn;

  WITH new_values (rest_id, rev_id, review, tm) as (values (restaurant_id, reviewer_id, review, current_timestamp)),
  upsert as
  ( 
      UPDATE reviews m 
          SET restaurant_id = nv.rest_id,
              reviewer_id = nv.rev_id,
              review = nv.review,
              review_posted = tm
      FROM new_values nv
      WHERE m.restaurant_id = nv.rest_id AND m.reviewer_id = nv.rev_id
      RETURNING m.*
  )
  INSERT INTO reviews (restaurant_id, reviewer_id, review)
  SELECT rest_id, rev_id, new_values.review
  FROM new_values
  WHERE NOT EXISTS (SELECT 1 
                    FROM upsert up 
                    WHERE up.restaurant_id = new_values.rest_id AND up.reviewer_id = new_values.rev_id);
END;
$$ LANGUAGE plpgsql;

-- Test Data
INSERT INTO restaurants  (restaurant_name, short_name) VALUES
  ('Vigilante Coffee', 'vigilante-coffee'),
  ('The Coffee Bar', 'the-coffee-bar'),
  ('Peregrine Espresso', 'peregrine-espresso'),
  ('Graffiato', 'graffiato');

INSERT INTO reviewers (reviewer_name) VALUES
  ('the_tooth_fairy'),
  ('fiddlerwoaroof'),
  ('grandma_johnson');

INSERT INTO reviews (reviewer_id, restaurant_id, review) VALUES
  ((SELECT id FROM reviewers where reviewer_name='the_tooth_fairy'), (SELECT id FROM restaurants where short_name='vigilante-coffee'), 'Great Coffee!'),
  ((SELECT id FROM reviewers where reviewer_name='fiddlerwoaroof'),  (SELECT id FROM restaurants where short_name='vigilante-coffee'), 'My coffee was cold :/'),
  ((SELECT id FROM reviewers where reviewer_name='grandma_johnson'), (SELECT id FROM restaurants where short_name='vigilante-coffee'), 'Bad Customer service, will actively avoid!'),
  ((SELECT id FROM reviewers where reviewer_name='the_tooth_fairy'), (SELECT id FROM restaurants where short_name='peregrine-espresso'), 'The owner looked at me funny,  do not return!'),
  ((SELECT id FROM reviewers where reviewer_name='fiddlerwoaroof'),  (SELECT id FROM restaurants where short_name='peregrine-espresso'), 'Great Coffee!'),
  ((SELECT id FROM reviewers where reviewer_name='grandma_johnson'), (SELECT id FROM restaurants where short_name='peregrine-espresso'), 'Cockroach in bottom of french press, disgusting!'),
  ((SELECT id FROM reviewers where reviewer_name='the_tooth_fairy'), (SELECT id FROM restaurants where short_name='graffiato'), 'Too Italian'),
  ((SELECT id FROM reviewers where reviewer_name='fiddlerwoaroof'),  (SELECT id FROM restaurants where short_name='graffiato'), 'They dont have a peanut butter pizza!'),
  ((SELECT id FROM reviewers where reviewer_name='grandma_johnson'), (SELECT id FROM restaurants where short_name='graffiato'), 'Whatever . . . '),
  ((SELECT id FROM reviewers where reviewer_name='the_tooth_fairy'), (SELECT id FROM restaurants where short_name='the-coffee-bar'), 'Great Location! Good Coffee!'),
  ((SELECT id FROM reviewers where reviewer_name='fiddlerwoaroof'),  (SELECT id FROM restaurants where short_name='the-coffee-bar'), 'Great Coffee! Good Location!'),
  ((SELECT id FROM reviewers where reviewer_name='grandma_johnson'), (SELECT id FROM restaurants where short_name='the-coffee-bar'), 'This is too far from my knitting needles . . . ');

SELECT * FROM reviews
  RIGHT JOIN reviewers ON reviews.reviewer_id=reviewers.id
  RIGHT JOIN restaurants ON reviews.restaurant_id=restaurants.id
  WHERE short_name='vigilante-coffee';

INSERT INTO reviewers (reviewer_name) VALUES ('the_great_one'); 
